Cómo implementar la función Rate It en la aplicación de Android

94

Estoy desarrollando una aplicación para Android. En el que todo va bien. Mi aplicación está lista para iniciarse. Pero ahí necesito implementar una característica más. Necesito mostrar una ventana emergente que contenga

Rate It y Remind me later

Aquí, si algún usuario califica la aplicación en el mercado, la ventana emergente no desaparecerá. Busqué en Google y encontré un enlace . Con esto entiendo que no es posible saberlo. Entonces necesito una sugerencia para esto.

¿Alguien se ha enfrentado a esta situación antes? Si es así, ¿hay alguna solución o alternativa para esto?

Naveen
fuente
Entonces, ¿está pidiendo solo Calificarlo / recordarme más tarde o está preguntando cómo saber si un usuario específico ha calificado una aplicación de Android?
wtsang02
1
He implementado la ventana emergente. pero cómo saber si un usuario califica la aplicación o no
Naveen
-1 No veo la diferencia entre esta pregunta y la del enlace.
wtsang02
2
@ wtsang02, puede que sea cierto. Pero mira la pregunta. se pregunta Mar 15 2011. casi 20 meses más. Creo que alguien tiene una solución o alternativa para mi requerimiento. eso es yi publicado aquí.
Naveen
Puede usar la biblioteca github.com/Vorlonsoft/AndroidRate ( implementation 'com.vorlonsoft:androidrate:1.0.3')
Alexander Savin

Respuestas:

180

Implementé esto hace un tiempo, hasta cierto punto. Es imposible saber si un usuario ha calificado una aplicación, para evitar que las calificaciones se conviertan en una moneda (algunos desarrolladores pueden agregar una opción como "Calificar esta aplicación y obtener fulano en la aplicación gratis").

La clase que escribí proporciona tres botones y configura el cuadro de diálogo para que solo se muestre después de que se haya iniciado la aplicación n(los usuarios tienen una mayor probabilidad de calificar la aplicación si la han usado un poco antes. La mayoría de ellos es poco probable para saber incluso lo que hace en la primera ejecución):

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 la clase es tan simple como agregar:

AppRater.app_launched(this);

A tu actividad. Solo necesita agregarse a una actividad en toda la aplicación.

Raghav Sood
fuente
1
Esto no admite que varios usuarios utilicen el mismo dispositivo.
AsafK
1
@AsafK Sí, pero se pueden manejar varios usuarios que utilizan el mismo dispositivo mostrando el appratercuadro de diálogo solo después de la autenticación y cambiando shared preferencepara incluir la dirección de correo electrónico de Google en el key.
Stephen
1
Hola, solo tengo una pregunta. ¿Por qué hiciste todo estático? ¡Gracias Raghav!
Ruchir Baronia
2
Hola, estoy probando tu código anterior. He puesto AppRater.app_launched(this);dentro de mi onCreate()MainActivity. También cambié el número mínimo de lanzamientos requeridos a 2. Pero no veo el cuadro de diálogo después del lanzamiento de 2 aplicaciones. ¿Me puedes ayudar? ¡Gracias!
Excepción
1
Mejor use la enumeración Context.MODE_PRIVATE-context.getSharedPreferences("apprater", Context.MODE_PRIVATE);
Vivek
18

El mío 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();
    }
}

Luego utilícelo en onCreate()su FragmentActivity principal:

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

    RateItDialogFragment.show(this, getFragmentManager());

}
mixel
fuente
¡Buena! Solo pondría el editor.commit () antes de mostrar DialogFragment en caso de que algo salga mal al cargar el Dialog.
narko
@narko Gracias. Actualizado.
Mixel
Nota: Puede provocar una pérdida de memoria si utiliza para solicitar guardar la preferencia compartida. Si observa cuidadosamente en setPositiveButtony setNegativeButton, está escribiendo en las preferencias compartidas usando commit, pero si usa apply, que es asíncrono y mantendrá la referencia a la actividad hasta que se complete y justo después de eso, llamará a despedir. Dismiss intentará destruir el fragmento, pero no puede porque la actividad es retenida / utilizada por el proceso de solicitud de preferencia compartida. (Lo usé porque AndroidStudio le pedirá al usuario que cambie la confirmación para aplicar, no lo haga a menos que usted use alguna otra lógica)
Sai
@mixel ¿Cómo modificar código para poder usarlo en Activity y sin fragmento?
user1090751
7

Creo que lo que está intentando hacer probablemente sea contraproducente.

Facilitar que las personas califiquen las aplicaciones es generalmente una buena idea, ya que la mayoría de las personas que se molestan lo hacen porque les gusta la aplicación. Se rumorea que la cantidad de calificaciones afecta su calificación de mercado (aunque veo poca evidencia de esto). Es probable que molestar a los usuarios para que califiquen, a través de pantallas de regaño, haga que las personas eliminen la queja al dejar una mala calificación.

Agregar la capacidad de calificar directamente una aplicación ha provocado una ligera disminución en las calificaciones numéricas de mi versión gratuita y un ligero aumento en mi aplicación paga. Para la aplicación gratuita, mis calificaciones de 4 estrellas aumentaron más que mis calificaciones de 5 estrellas, ya que las personas que pensaban que mi aplicación era buena pero no excelente comenzaron a calificarla también. El cambio fue de aproximadamente -0,2. Para los pagos, el cambio fue de aproximadamente +0,1. Debería eliminarlo de la versión gratuita, excepto que me gusta recibir muchos comentarios.

Pongo mi botón de calificación en una pantalla de configuración (preferencia), donde no afecta el funcionamiento normal. Aún así, aumentó mi índice de calificación en un factor de 4 o 5. No tengo ninguna duda de que si intentara molestar a mis usuarios para que hagan una calificación, obtendría muchos usuarios que me daban malas calificaciones como protesta.

Peter Webb
fuente
100% cierto. Lo mismo sucedió con mi aplicación gratuita también.
Akash Varlani
7

AndroidRate es una biblioteca para ayudarlo a promocionar su aplicación de Android al pedirles a los usuarios que califiquen la aplicación después de usarla durante unos días.

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);
  }
}

Las condiciones predeterminadas para mostrar el cuadro de diálogo de tasas son las siguientes:

  1. La aplicación se inicia más de 10 días después de la instalación. Cambiar vía AppRate#setInstallDays(byte).
  2. La aplicación se lanza más de 10 veces. Cambiar vía AppRate#setLaunchTimes(byte).
  3. La aplicación se inicia más de 1 día después de hacer clic en el botón neutral. Cambiar vía AppRate#setRemindInterval(byte).
  4. La aplicación se inicia X veces y X% 1 = 0. Cambiar mediante AppRate#setRemindLaunchTimes(byte).
  5. La aplicación muestra un cuadro de diálogo neutral (Recordármelo más tarde) de forma predeterminada. Cambiar vía setShowLaterButton(boolean).
  6. Para especificar la devolución de llamada cuando se presiona el botón. Se DialogInterface.OnClickListener#onClickpasará el mismo valor que el segundo argumento de en el argumento de onClickButton.
  7. La configuración AppRate#setDebug(boolean)garantizará que la solicitud de calificación se muestre cada vez que se inicia la aplicación. ¡Esta característica es solo para desarrollo! .

Requisitos de eventos personalizados opcionales para mostrar el diálogo

Puede agregar requisitos opcionales adicionales para mostrar el diálogo. Cada requisito se puede agregar / referenciar como una cadena única. Puede establecer un recuento mínimo para cada uno de estos eventos (por ejemplo, "action_performed" 3 veces, "button_clicked" 5 veces, etc.)

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

Borrar el indicador de diálogo de mostrar

Cuando desee volver a mostrar el cuadro de diálogo, llame AppRate#clearAgreeShowDialog().

AppRate.with(this).clearAgreeShowDialog();

Cuando el botón presiona

llamar AppRate#showRateDialog(Activity).

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

Establecer vista personalizada

llamar 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

Puede utilizar un tema específico para inflar el diálogo.

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

Diálogo personalizado

Si desea utilizar sus propias etiquetas de diálogo, anule los recursos xml de cadena en su aplicación.

<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>

Comprueba que Google Play esté disponible

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

}
Alexander Savin
fuente
3

Esta solución es muy similar a las presentadas anteriormente. La única diferencia es que podrá retrasar la solicitud del cuadro de diálogo de calificación por lanzamientos y días. Si se presiona el botón Recordarme más tarde, retrasaré la ventana emergente durante 3 días y 10 inicios. Lo mismo se hace para aquellos que seleccionaron calificarla, sin embargo, los retrasos son más largos (para no molestar al usuario tan pronto en caso de que realmente haya calificado la aplicación. Esto se puede cambiar para que no se muestre nuevamente, entonces tendrá que modifique el código a su gusto). ¡Espero que ayude a alguien!

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();
    }
}

Los botones tienen un color y un fondo específicos. El fondo es como se muestra en este archivo 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>

fuente: enfoque de Android para "Calificar mi aplicación"

Gustavo Baiocchi Costa
fuente
Lo que es "Configs" no se encuentra cuando lo intento.
Md Imran Choudhury
1
@ Md.ImranChoudhury Perdón por la respuesta tardía. Las configuraciones son una clase privada mía que utilizo para Google Analytics. ¡Puede eliminar esa declaración sin ningún problema!
Gustavo Baiocchi Costa
debe vincularlo a la respuesta original o darle crédito. stackoverflow.com/a/6920848/563735
Rohit Mandiwal
1

Como puede ver en la otra publicación que ha vinculado, no hay forma de que la aplicación sepa si el usuario ha dejado una reseña o no. Y por una buena razón.

Piénselo, si una aplicación pudiera decir si el usuario ha dejado una reseña o no, el desarrollador podría restringir ciertas funciones que solo se desbloquearían si el usuario deja una calificación de 5/5. Esto llevaría a los otros usuarios de Google Play a no confiar en las reseñas y socavaría el sistema de calificación.

Las soluciones alternativas que he visto es que la aplicación le recuerda al usuario que envíe una calificación cada vez que la aplicación se abre una cantidad específica de veces o un intervalo establecido. Por ejemplo, cada décima vez que se abre la aplicación, pida al usuario que deje una calificación y proporcione un botón "ya hecho" y "recordarme más tarde". Sigue mostrando este mensaje si el usuario ha optado por recordárselo más tarde. Algunos otros desarrolladores de aplicaciones muestran este mensaje con un intervalo creciente (como 5, 10, 15ª vez que se abre la aplicación), porque si un usuario no ha dejado una reseña, por ejemplo, la 100ª vez que se abrió la aplicación, es probablemente no dejará uno.

Esta solución no es perfecta, pero creo que es la mejor que tienes por ahora. Te lleva a confiar en el usuario, pero te das cuenta de que la alternativa significaría una experiencia potencialmente peor para todos en el mercado de aplicaciones.

Vidhur Vohra
fuente
1

Solución Java y Kotlin (API de revisión en la aplicación de Google en 2020):

ingrese la descripción de la imagen aquí

Primero, en su build.gradle(app)archivo, agregue las siguientes dependencias (configuración completa aquí )

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'
}

Agregue este método a su 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.
        }
    });
}

Llámalo como cualquier otro método:

askRatings();

El código de Kotlin se puede encontrar aquí

iLoveDocs
fuente
0

Versión de Kotlin de la respuesta 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()
            }
        }
    }
}

Respuesta optimizada

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>
Víctor R. Oliveira
fuente