Como implementar o recurso Rate It no aplicativo Android

94

Estou desenvolvendo um aplicativo Android. Em que tudo está funcionando direito. Meu aplicativo está pronto para iniciar. Mas aí eu preciso implementar mais um recurso. Preciso exibir um pop-up que contém

Rate It e Remind me later

Aqui, se algum usuário avaliar o aplicativo no mercado, o pop-up não desaparecerá. Eu pesquisei no Google e encontrei um link . Com isso eu entendo que não é possível saber. Portanto, preciso de uma sugestão para isso.

Alguém já enfrentou essa situação antes? Em caso afirmativo, existe alguma solução ou alternativa para isso?

Naveen
fonte
Então, você está perguntando apenas sobre Avaliar / lembrar mais tarde ou como saber se um usuário específico avaliou um aplicativo Android?
wtsang02
1
Eu implementei o pop-up. mas como saber se um usuário avaliou o aplicativo ou não
Naveen
-1 Não vejo diferença entre esta pergunta e a do link.
wtsang02
2
@ wtsang02, pode ser verdade. Mas veja a pergunta. é solicitado Mar 15 2011. então quase 20 meses se passaram. Acho que alguém tem solução ou alternativa para minha necessidade. que você postou aqui.
Naveen
Você pode usar a biblioteca github.com/Vorlonsoft/AndroidRate ( implementation 'com.vorlonsoft:androidrate:1.0.3')
Alexander Savin

Respostas:

180

Eu implementei isso há um tempo, até certo ponto. É impossível saber se um usuário avaliou um aplicativo ou não, para evitar que as avaliações se tornem uma moeda (alguns desenvolvedores podem adicionar uma opção como "Avalie este aplicativo e obtenha fulano no aplicativo gratuitamente").

A classe que escrevi fornece três botões e configura a caixa de diálogo para que ela seja mostrada apenas depois que o aplicativo for iniciado nvezes (os usuários têm uma chance maior de classificar o aplicativo se o usarem um pouco antes. A maioria deles é improvável saber até mesmo o que faz na primeira execução):

public class AppRater {
    private final static String APP_TITLE = "App Name";// App Name
    private final static String APP_PNAME = "com.example.name";// Package Name

    private final static int DAYS_UNTIL_PROMPT = 3;//Min number of days
    private final static int LAUNCHES_UNTIL_PROMPT = 3;//Min number of launches

    public static void app_launched(Context mContext) {
        SharedPreferences prefs = mContext.getSharedPreferences("apprater", 0);
        if (prefs.getBoolean("dontshowagain", false)) { return ; }

        SharedPreferences.Editor editor = prefs.edit();

        // Increment launch counter
        long launch_count = prefs.getLong("launch_count", 0) + 1;
        editor.putLong("launch_count", launch_count);

        // Get date of first launch
        Long date_firstLaunch = prefs.getLong("date_firstlaunch", 0);
        if (date_firstLaunch == 0) {
            date_firstLaunch = System.currentTimeMillis();
            editor.putLong("date_firstlaunch", date_firstLaunch);
        }

        // Wait at least n days before opening
        if (launch_count >= LAUNCHES_UNTIL_PROMPT) {
            if (System.currentTimeMillis() >= date_firstLaunch + 
                    (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)) {
                showRateDialog(mContext, editor);
            }
        }

        editor.commit();
    }   

    public static void showRateDialog(final Context mContext, final SharedPreferences.Editor editor) {
        final Dialog dialog = new Dialog(mContext);
        dialog.setTitle("Rate " + APP_TITLE);

        LinearLayout ll = new LinearLayout(mContext);
        ll.setOrientation(LinearLayout.VERTICAL);

        TextView tv = new TextView(mContext);
        tv.setText("If you enjoy using " + APP_TITLE + ", please take a moment to rate it. Thanks for your support!");
        tv.setWidth(240);
        tv.setPadding(4, 0, 4, 10);
        ll.addView(tv);

        Button b1 = new Button(mContext);
        b1.setText("Rate " + APP_TITLE);
        b1.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APP_PNAME)));
                dialog.dismiss();
            }
        });        
        ll.addView(b1);

        Button b2 = new Button(mContext);
        b2.setText("Remind me later");
        b2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        ll.addView(b2);

        Button b3 = new Button(mContext);
        b3.setText("No, thanks");
        b3.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (editor != null) {
                    editor.putBoolean("dontshowagain", true);
                    editor.commit();
                }
                dialog.dismiss();
            }
        });
        ll.addView(b3);

        dialog.setContentView(ll);        
        dialog.show();        
    }
}

Integrar a classe é tão simples quanto adicionar:

AppRater.app_launched(this);

Para sua atividade. Ele só precisa ser adicionado a uma atividade em todo o aplicativo.

Raghav Sood
fonte
1
Isso não oferece suporte a vários usuários usando o mesmo dispositivo.
AsafK de
1
@AsafK Sim, mas vários usuários usando o mesmo dispositivo podem ser tratados mostrando a appratercaixa de diálogo apenas após a autenticação e alterando shared preferencepara incluir o endereço de e-mail do Google no key.
stephen,
1
Olá, tenho apenas uma pergunta. Por que você fez tudo estático? Obrigado Raghav!
Ruchir Baronia de
2
Olá, estou tentando seu código acima. Eu coloquei AppRater.app_launched(this);dentro do meu onCreate()de MainActivity. Eu também alterei o número mínimo de inicializações necessárias para 2. Mas, não estou vendo a caixa de diálogo após a inicialização de 2 aplicativos. Você pode me ajudar? Obrigado!
Exceção
1
Melhor usar o enum Context.MODE_PRIVATE-context.getSharedPreferences("apprater", Context.MODE_PRIVATE);
Vivek
18

Meu único usando DialogFragment:

public class RateItDialogFragment extends DialogFragment {
    private static final int LAUNCHES_UNTIL_PROMPT = 10;
    private static final int DAYS_UNTIL_PROMPT = 3;
    private static final int MILLIS_UNTIL_PROMPT = DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000;
    private static final String PREF_NAME = "APP_RATER";
    private static final String LAST_PROMPT = "LAST_PROMPT";
    private static final String LAUNCHES = "LAUNCHES";
    private static final String DISABLED = "DISABLED";

    public static void show(Context context, FragmentManager fragmentManager) {
        boolean shouldShow = false;
        SharedPreferences sharedPreferences = getSharedPreferences(context);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        long currentTime = System.currentTimeMillis();
        long lastPromptTime = sharedPreferences.getLong(LAST_PROMPT, 0);
        if (lastPromptTime == 0) {
            lastPromptTime = currentTime;
            editor.putLong(LAST_PROMPT, lastPromptTime);
        }

        if (!sharedPreferences.getBoolean(DISABLED, false)) {
            int launches = sharedPreferences.getInt(LAUNCHES, 0) + 1;
            if (launches > LAUNCHES_UNTIL_PROMPT) {
                if (currentTime > lastPromptTime + MILLIS_UNTIL_PROMPT) {
                    shouldShow = true;
                }
            }
            editor.putInt(LAUNCHES, launches);
        }

        if (shouldShow) {
            editor.putInt(LAUNCHES, 0).putLong(LAST_PROMPT, System.currentTimeMillis()).commit();
            new RateItDialogFragment().show(fragmentManager, null);
        } else {
            editor.commit();
        }
    }

    private static SharedPreferences getSharedPreferences(Context context) {
        return context.getSharedPreferences(PREF_NAME, 0);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setTitle(R.string.rate_title)
                .setMessage(R.string.rate_message)
                .setPositiveButton(R.string.rate_positive, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getActivity().getPackageName())));
                        getSharedPreferences(getActivity()).edit().putBoolean(DISABLED, true).commit();
                        dismiss();
                    }
                })
                .setNeutralButton(R.string.rate_remind_later, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dismiss();
                    }
                })
                .setNegativeButton(R.string.rate_never, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        getSharedPreferences(getActivity()).edit().putBoolean(DISABLED, true).commit();
                        dismiss();
                    }
                }).create();
    }
}

Em seguida, use-o em onCreate()sua FragmentActivity principal:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

    RateItDialogFragment.show(this, getFragmentManager());

}
mixel
fonte
Um bom! Eu colocaria apenas editor.commit () antes de mostrar o DialogFragment, para o caso de algo dar errado ao carregar o Dialog.
narko
@narko Obrigado. Atualizada.
mixel de
Nota: Isso pode levar a um vazamento de memória se você usar para aplicar para salvar a preferência compartilhada. Se você observar cuidadosamente em setPositiveButtone setNegativeButton, está escrevendo para preferências compartilhadas usando commit, mas se você usar apply, que é assíncrono e manterá a referência à atividade até que ela seja concluída e logo depois disso está chamando de ignorar. Dismiss tentará destruir o fragmento, mas não pode porque a atividade é mantida / usada pelo processo de aplicação de preferência compartilhada. (Usei isso porque o AndroidStudio solicitará que o usuário altere o commit para aplicar, não faça isso a menos que você use alguma outra lógica)
Sai
@mixel Como modificar o código para poder usar em Activity e sem fragmento?
user1090751
7

Acho que o que você está tentando fazer é provavelmente contraproducente.

Facilitar a avaliação dos aplicativos é geralmente uma boa ideia, já que a maioria das pessoas que se preocupam faz isso porque gostam do aplicativo. Há rumores de que o número de classificações afeta sua classificação de mercado (embora eu veja poucas evidências disso). Insistir para que os usuários classifiquem - por meio de telas de reclamação - provavelmente fará com que as pessoas eliminem a reclamação por meio de uma classificação ruim.

Adicionar a capacidade de classificar diretamente um aplicativo causou uma ligeira diminuição nas classificações numéricas da minha versão gratuita e um ligeiro aumento no meu aplicativo pago. Para o aplicativo gratuito, minhas avaliações de 4 estrelas aumentaram mais do que minhas avaliações de 5 estrelas, pois as pessoas que pensavam que meu aplicativo era bom, mas não muito bom, começaram a avaliá-lo também. A mudança foi de cerca de -0,2. Para os pagos, a variação foi de cerca de +0,1. Devo removê-lo da versão gratuita, mas gosto de receber muitos comentários.

Coloquei meu botão de classificação em uma tela de configurações (preferências), onde ele não afeta a operação normal. Ainda aumentou minha taxa de classificação por um fator de 4 ou 5. Não tenho dúvidas de que, se tentasse persuadir meus usuários a fazerem uma classificação, muitos usuários me dariam classificações ruins em protesto.

Peter Webb
fonte
100% verdade. A mesma coisa aconteceu com meu aplicativo gratuito também.
akash varlani
7

AndroidRate é uma biblioteca para ajudá-lo a promover seu aplicativo Android, solicitando aos usuários que avaliem o aplicativo depois de usá-lo por alguns dias.

Módulo Gradle:

dependencies {
  implementation 'com.vorlonsoft:androidrate:1.0.8'
}

MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  AppRate.with(this)
      .setStoreType(StoreType.GOOGLEPLAY) //default is GOOGLEPLAY (Google Play), other options are
                                          //           AMAZON (Amazon Appstore) and
                                          //           SAMSUNG (Samsung Galaxy Apps)
      .setInstallDays((byte) 0) // default 10, 0 means install day
      .setLaunchTimes((byte) 3) // default 10
      .setRemindInterval((byte) 2) // default 1
      .setRemindLaunchTimes((byte) 2) // default 1 (each launch)
      .setShowLaterButton(true) // default true
      .setDebug(false) // default false
      //Java 8+: .setOnClickButtonListener(which -> Log.d(MainActivity.class.getName(), Byte.toString(which)))
      .setOnClickButtonListener(new OnClickButtonListener() { // callback listener.
          @Override
          public void onClickButton(byte which) {
              Log.d(MainActivity.class.getName(), Byte.toString(which));
          }
      })
      .monitor();

  if (AppRate.with(this).getStoreType() == StoreType.GOOGLEPLAY) {
      //Check that Google Play is available
      if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING) {
          // Show a dialog if meets conditions
          AppRate.showRateDialogIfMeetsConditions(this);
      }
  } else {
      // Show a dialog if meets conditions
      AppRate.showRateDialogIfMeetsConditions(this);
  }
}

As condições padrão para mostrar a caixa de diálogo de taxas são as seguintes:

  1. O aplicativo é lançado mais de 10 dias após a instalação. Alterar via AppRate#setInstallDays(byte).
  2. O aplicativo é iniciado mais de 10 vezes. Alterar via AppRate#setLaunchTimes(byte).
  3. O aplicativo é lançado mais de 1 dia após o clique do botão neutro. Alterar via AppRate#setRemindInterval(byte).
  4. O aplicativo é iniciado X vezes e X% 1 = 0. Alterar via AppRate#setRemindLaunchTimes(byte).
  5. O aplicativo mostra uma caixa de diálogo neutra (Lembre-me mais tarde) por padrão. Alterar via setShowLaterButton(boolean).
  6. Para especificar o retorno de chamada quando o botão é pressionado. O mesmo valor que o segundo argumento de DialogInterface.OnClickListener#onClickserá passado no argumento de onClickButton.
  7. A configuração AppRate#setDebug(boolean)garantirá que a solicitação de classificação seja exibida sempre que o aplicativo for iniciado. Este recurso é apenas para desenvolvimento! .

Requisitos opcionais de eventos personalizados para mostrar a caixa de diálogo

Você pode adicionar requisitos opcionais adicionais para mostrar a caixa de diálogo. Cada requisito pode ser adicionado / referenciado como uma string exclusiva. Você pode definir uma contagem mínima para cada evento (por exemplo, "action_performed" 3 vezes, "button_clicked" 5 vezes, etc.)

AppRate.with(this).setMinimumEventCount(String, short);
AppRate.with(this).incrementEventCount(String);
AppRate.with(this).setEventCountValue(String, short);

Limpar sinalizador de diálogo de exibição

Quando você quiser mostrar o diálogo novamente, chame AppRate#clearAgreeShowDialog().

AppRate.with(this).clearAgreeShowDialog();

Quando o botão é pressionado

ligue AppRate#showRateDialog(Activity).

AppRate.with(this).showRateDialog(this);

Definir visualização personalizada

ligue AppRate#setView(View).

LayoutInflater inflater = (LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.custom_dialog, (ViewGroup)findViewById(R.id.layout_root));
AppRate.with(this).setView(view).monitor();

Tema específico

Você pode usar um tema específico para aumentar o diálogo.

AppRate.with(this).setThemeResId(int);

Diálogo personalizado

Se você quiser usar seus próprios rótulos de diálogo, substitua os recursos xml de string em seu aplicativo.

<resources>
    <string name="rate_dialog_title">Rate this app</string>
    <string name="rate_dialog_message">If you enjoy playing this app, would you mind taking a moment to rate it? It won\'t take more than a minute. Thanks for your support!</string>
    <string name="rate_dialog_ok">Rate It Now</string>
    <string name="rate_dialog_cancel">Remind Me Later</string>
    <string name="rate_dialog_no">No, Thanks</string>
</resources>

Verifique se o Google Play está disponível

if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING) {

}
Alexander Savin
fonte
3

Esta solução é muito semelhante às apresentadas acima. A única diferença é que você poderá atrasar o prompt do diálogo de classificação por lançamentos e dias. Se o botão Lembrar mais tarde for pressionado, atrasarei o pop-up por 3 dias e 10 lançamentos. O mesmo é feito para aqueles que selecionaram para avaliá-lo, porém os atrasos são maiores (para não incomodar o usuário tão cedo no caso de ele realmente ter avaliado o aplicativo. Isso pode ser alterado para não ser mostrado novamente, então você terá que altere o código ao seu gosto). Espero que ajude alguém!

public class AppRater {
    private final static String APP_TITLE = "your_app_name";
    private static String PACKAGE_NAME = "your_package_name";
    private static int DAYS_UNTIL_PROMPT = 5;
    private static int LAUNCHES_UNTIL_PROMPT = 10;
    private static long EXTRA_DAYS;
    private static long EXTRA_LAUCHES;
    private static SharedPreferences prefs;
    private static SharedPreferences.Editor editor;
    private static Activity activity;

    public static void app_launched(Activity activity1) {
        activity = activity1;

        Configs.sendScreenView("Avaliando App", activity);

        PACKAGE_NAME = activity.getPackageName();

        prefs = activity.getSharedPreferences("apprater", Context.MODE_PRIVATE);
        if (prefs.getBoolean("dontshowagain", false)) 
            return;

        editor = prefs.edit();

        EXTRA_DAYS = prefs.getLong("extra_days", 0);
        EXTRA_LAUCHES = prefs.getLong("extra_launches", 0);

        // Increment launch counter
        long launch_count = prefs.getLong("launch_count", 0) + 1;
        editor.putLong("launch_count", launch_count);

        // Get date of first launch
        Long date_firstLaunch = prefs.getLong("date_firstlaunch", 0);
        if (date_firstLaunch == 0) {
            date_firstLaunch = System.currentTimeMillis();
            editor.putLong("date_firstlaunch", date_firstLaunch);
        }

        // Wait at least n days before opening
        if (launch_count >= (LAUNCHES_UNTIL_PROMPT + EXTRA_LAUCHES))
            if (System.currentTimeMillis() >= date_firstLaunch + (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000) + EXTRA_DAYS)
                showRateDialog();

        editor.commit();
    }   

    public static void showRateDialog() {
        final Dialog dialog = new Dialog(activity);
        dialog.setTitle("Deseja avaliar o aplicativo " + APP_TITLE + "?");

        LinearLayout ll = new LinearLayout(activity);
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.setPadding(5, 5, 5, 5);

        TextView tv = new TextView(activity);
        tv.setTextColor(activity.getResources().getColor(R.color.default_text));
        tv.setText("Ajude-nos a melhorar o aplicativo com sua avaliação no Google Play!");
        tv.setWidth(240);
        tv.setGravity(Gravity.CENTER);
        tv.setPadding(5, 5, 5, 5);
        ll.addView(tv);

        Button b1 = new Button(activity);
        b1.setTextColor(activity.getResources().getColor(R.color.default_text));
        b1.setBackground(activity.getResources().getDrawable(R.drawable.rounded_blue_box));
        b1.setTextColor(Color.WHITE);
        b1.setText("Avaliar aplicativo " + APP_TITLE + "!");
        b1.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Configs.sendHitEvents(Configs.APP_RATER, Configs.CATEGORIA_ANALYTICS, "Clique", "Avaliar", activity);

                activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + PACKAGE_NAME)));
                delayDays(60);
                delayLaunches(30);
                dialog.dismiss();
            }
        });        
        ll.addView(b1);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) b1.getLayoutParams();
        params.setMargins(5, 3, 5, 3);
        b1.setLayoutParams(params);

        Button b2 = new Button(activity);
        b2.setTextColor(activity.getResources().getColor(R.color.default_text));
        b2.setBackground(activity.getResources().getDrawable(R.drawable.rounded_blue_box));
        b2.setTextColor(Color.WHITE);
        b2.setText("Lembre-me mais tarde!");
        b2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Configs.sendHitEvents(Configs.APP_RATER, Configs.CATEGORIA_ANALYTICS, "Clique", "Avaliar Mais Tarde", activity);
                delayDays(3);
                delayLaunches(10);
                dialog.dismiss();
            }
        });
        ll.addView(b2);
        params = (LinearLayout.LayoutParams) b2.getLayoutParams();
        params.setMargins(5, 3, 5, 3);
        b2.setLayoutParams(params);

        Button b3 = new Button(activity);
        b3.setTextColor(activity.getResources().getColor(R.color.default_text));
        b3.setBackground(activity.getResources().getDrawable(R.drawable.rounded_blue_box));
        b3.setTextColor(Color.WHITE);
        b3.setText("Não, obrigado!");
        b3.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Configs.sendHitEvents(Configs.APP_RATER, Configs.CATEGORIA_ANALYTICS, "Clique", "Não Avaliar", activity);

                if (editor != null) {
                    editor.putBoolean("dontshowagain", true);
                    editor.commit();
                }
                dialog.dismiss();
            }
        });
        ll.addView(b3);
        params = (LinearLayout.LayoutParams) b3.getLayoutParams();
        params.setMargins(5, 3, 5, 0);
        b3.setLayoutParams(params);

        dialog.setContentView(ll);        
        dialog.show();        
    }

    private static void delayLaunches(int numberOfLaunches) {
        long extra_launches = prefs.getLong("extra_launches", 0) + numberOfLaunches;
        editor.putLong("extra_launches", extra_launches);
        editor.commit();
    }

    private static void delayDays(int numberOfDays) {
        Long extra_days = prefs.getLong("extra_days", 0) + (numberOfDays * 1000 * 60 * 60 * 24);
        editor.putLong("extra_days", extra_days);
        editor.commit();
    }
}

Os botões têm cor e fundo específicos. O plano de fundo é como mostrado neste arquivo xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="10dp"
    android:shape="rectangle" >

    <solid android:color="#2E78B9" />

    <corners
        android:bottomLeftRadius="6dp"
        android:bottomRightRadius="6dp"
        android:topLeftRadius="6dp"
        android:topRightRadius="6dp" />

</shape>

fonte: abordagem Android para "Avalie meu aplicativo"

Gustavo Baiocchi Costa
fonte
O que é "Configs" não foi encontrado quando tento.
Md Imran Choudhury
1
@ Md.ImranChoudhury Desculpe pela resposta tardia. O configs é uma aula particular minha que uso para o google analytics. Você pode simplesmente remover essa declaração sem problemas!
Gustavo Baiocchi Costa
você deve criar um link para a resposta original ou dar crédito a ele. stackoverflow.com/a/6920848/563735
Rohit Mandiwal
1

Como você pode ver na outra postagem que você vinculou, não há como o aplicativo saber se o usuário deixou um comentário ou não. E por um bom motivo.

Pense nisso, se um aplicativo pudesse dizer se o usuário deixou um comentário ou não, o desenvolvedor poderia restringir certos recursos que só seriam desbloqueados se o usuário deixasse uma classificação de 5/5. Isso levaria os outros usuários do Google Play a não confiar nas avaliações e prejudicaria o sistema de classificação.

As soluções alternativas que vi é que o aplicativo lembra o usuário de enviar uma classificação sempre que o aplicativo é aberto um determinado número de vezes ou um intervalo definido. Por exemplo, a cada dez vezes que o aplicativo for aberto, peça ao usuário para deixar uma avaliação e fornecer um botão "já concluído" e "lembre-me mais tarde". Continue mostrando esta mensagem se o usuário tiver optado por lembrá-lo mais tarde. Alguns outros desenvolvedores de aplicativos mostram esta mensagem com um intervalo crescente (como, 5, 10, 15ª vez que o aplicativo é aberto), porque se um usuário não deixou uma avaliação na, por exemplo, 100ª vez que o aplicativo foi aberto, é provavelmente ele / ela não deixará um.

Essa solução não é perfeita, mas acho que é o melhor que você tem por agora. Isso leva você a confiar no usuário, mas perceba que a alternativa significaria uma experiência potencialmente pior para todos no mercado de aplicativos.

Vidhur Vohra
fonte
1

Solução Java e Kotlin (API de revisão no aplicativo do Google em 2020):

insira a descrição da imagem aqui

Primeiro, em seu build.gradle(app)arquivo, adicione as seguintes dependências (configuração completa aqui )

dependencies {
    // This dependency is downloaded from the Google’s Maven repository.
    // So, make sure you also include that repository in your project's build.gradle file.
    implementation 'com.google.android.play:core:1.8.0'
}

Adicione este método ao seu Activity:

void askRatings() {
    ReviewManager manager = ReviewManagerFactory.create(this);
    Task<ReviewInfo> request = manager.requestReviewFlow();
    request.addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            // We can get the ReviewInfo object
            ReviewInfo reviewInfo = task.getResult();
            Task<Void> flow = manager.launchReviewFlow(this, reviewInfo);
            flow.addOnCompleteListener(task2 -> {
                // The flow has finished. The API does not indicate whether the user
                // reviewed or not, or even whether the review dialog was shown. Thus, no
                // matter the result, we continue our app flow.
            });
        } else {
            // There was some problem, continue regardless of the result.
        }
    });
}

Chame-o como qualquer outro método:

askRatings();

O código Kotlin pode ser encontrado aqui

iLoveDocs
fonte
0

Versão Kotlin da resposta de Raghav Sood

Rater.kt

    class Rater {
      companion object {
        private const val APP_TITLE = "App Name"
        private const val APP_NAME = "com.example.name"

        private const val RATER_KEY = "rater_key"
        private const val LAUNCH_COUNTER_KEY = "launch_counter_key"
        private const val DO_NOT_SHOW_AGAIN_KEY = "do_not_show_again_key"
        private const val FIRST_LAUNCH_KEY = "first_launch_key"

        private const val DAYS_UNTIL_PROMPT: Int = 3
        private const val LAUNCHES_UNTIL_PROMPT: Int = 3

        fun start(mContext: Context) {
            val prefs: SharedPreferences = mContext.getSharedPreferences(RATER_KEY, 0)
            if (prefs.getBoolean(DO_NOT_SHOW_AGAIN_KEY, false)) {
                return
            }

            val editor: Editor = prefs.edit()

            val launchesCounter: Long = prefs.getLong(LAUNCH_COUNTER_KEY, 0) + 1;
            editor.putLong(LAUNCH_COUNTER_KEY, launchesCounter)

            var firstLaunch: Long = prefs.getLong(FIRST_LAUNCH_KEY, 0)
            if (firstLaunch == 0L) {
                firstLaunch = System.currentTimeMillis()
                editor.putLong(FIRST_LAUNCH_KEY, firstLaunch)
            }

            if (launchesCounter >= LAUNCHES_UNTIL_PROMPT) {
                if (System.currentTimeMillis() >= firstLaunch +
                    (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)
                ) {
                    showRateDialog(mContext, editor)
                }
            }

            editor.apply()
        }

        fun showRateDialog(mContext: Context, editor: Editor) {
            Dialog(mContext).apply {
                setTitle("Rate $APP_TITLE")

                val ll = LinearLayout(mContext)
                ll.orientation = LinearLayout.VERTICAL

                TextView(mContext).apply {
                    text =
                        "If you enjoy using $APP_TITLE, please take a moment to rate it. Thanks for your support!"

                    width = 240
                    setPadding(4, 0, 4, 10)
                    ll.addView(this)
                }

                Button(mContext).apply {
                    text = "Rate $APP_TITLE"
                    setOnClickListener {
                        mContext.startActivity(
                            Intent(
                                Intent.ACTION_VIEW,
                                Uri.parse("market://details?id=$APP_NAME")
                            )
                        );
                        dismiss()
                    }
                    ll.addView(this)
                }

                Button(mContext).apply {
                    text = "Remind me later"
                    setOnClickListener {
                        dismiss()
                    };
                    ll.addView(this)
                }

                Button(mContext).apply {
                    text = "No, thanks"
                    setOnClickListener {
                        editor.putBoolean(DO_NOT_SHOW_AGAIN_KEY, true);
                        editor.commit()
                        dismiss()
                    };
                    ll.addView(this)
                }

                setContentView(ll)
                show()
            }
        }
    }
}

Resposta otimizada

Rater.kt

class Rater {
    companion object {
        fun start(context: Context) {
            val prefs: SharedPreferences = context.getSharedPreferences(RATER_KEY, 0)
            if (prefs.getBoolean(DO_NOT_SHOW_AGAIN_KEY, false)) {
                return
            }

            val editor: Editor = prefs.edit()

            val launchesCounter: Long = prefs.getLong(LAUNCH_COUNTER_KEY, 0) + 1;
            editor.putLong(LAUNCH_COUNTER_KEY, launchesCounter)

            var firstLaunch: Long = prefs.getLong(FIRST_LAUNCH_KEY, 0)
            if (firstLaunch == 0L) {
                firstLaunch = System.currentTimeMillis()
                editor.putLong(FIRST_LAUNCH_KEY, firstLaunch)
            }

            if (launchesCounter >= LAUNCHES_UNTIL_PROMPT) {
                if (System.currentTimeMillis() >= firstLaunch +
                    (DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000)
                ) {
                    showRateDialog(context, editor)
                }
            }

            editor.apply()
        }

        fun showRateDialog(context: Context, editor: Editor) {
            Dialog(context).apply {
                setTitle("Rate $APP_TITLE")
                LinearLayout(context).let { layout ->
                    layout.orientation = LinearLayout.VERTICAL
                    setDescription(context, layout)
                    setPositiveAnswer(context, layout)
                    setNeutralAnswer(context, layout)
                    setNegativeAnswer(context, editor, layout)
                    setContentView(layout)
                    show()       
                }
            }
        }

        private fun setDescription(context: Context, layout: LinearLayout) {
            TextView(context).apply {
                text = context.getString(R.string.rate_description, APP_TITLE)
                width = 240
                setPadding(4, 0, 4, 10)
                layout.addView(this)
            }
        }

        private fun Dialog.setPositiveAnswer(
            context: Context,
            layout: LinearLayout
        ) {
            Button(context).apply {
                text = context.getString(R.string.rate_now)
                setOnClickListener {
                    context.startActivity(
                        Intent(
                            Intent.ACTION_VIEW,
                            Uri.parse(context.getString(R.string.market_uri, APP_NAME))
                        )
                    );
                    dismiss()
                }
                layout.addView(this)
            }
        }

        private fun Dialog.setNeutralAnswer(
            context: Context,
            layout: LinearLayout
        ) {
            Button(context).apply {
                text = context.getString(R.string.remind_later)
                setOnClickListener {
                    dismiss()
                };
                layout.addView(this)
            }
        }

        private fun Dialog.setNegativeAnswer(
            context: Context,
            editor: Editor,
            layout: LinearLayout
        ) {
            Button(context).apply {
                text = context.getString(R.string.no_thanks)
                setOnClickListener {
                    editor.putBoolean(DO_NOT_SHOW_AGAIN_KEY, true);
                    editor.commit()
                    dismiss()
                };
                layout.addView(this)
            }
        }
    }
}

Constants.kt

object Constants {

    const val APP_TITLE = "App Name"
    const val APP_NAME = "com.example.name"

    const val RATER_KEY = "rater_key"
    const val LAUNCH_COUNTER_KEY = "launch_counter_key"
    const val DO_NOT_SHOW_AGAIN_KEY = "do_not_show_again_key"
    const val FIRST_LAUNCH_KEY = "first_launch_key"

    const val DAYS_UNTIL_PROMPT: Int = 3
    const val LAUNCHES_UNTIL_PROMPT: Int = 3

}

strings.xml

<resources>
    <string name="rate_description">If you enjoy using %1$s, please take a moment to rate it. Thanks for your support!</string>
    <string name="rate_now">Rate now</string>
    <string name="no_thanks">No, thanks</string>
    <string name="remind_later">Remind me later</string>
    <string name="market_uri">market://details?id=%1$s</string>
</resources>
Victor R. Oliveira
fonte