How to implement Rate It feature in Android App
Solution 1
I implemented this a while back, to some extent. It is impossible to know whether or not a user has rated an app, to prevent ratings from becoming a currency (some developers might add an option like "Rate this app and get so and so in the app for free").
The class I wrote provides three buttons, and configures the dialog so that it is only shown after the app has been launched n
times (users have a higher chance of rating the app if they've used it a bit before. Most of them are unlikely to even know what it does on the first run):
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();
}
}
Integrating the class is as simple as adding:
AppRater.app_launched(this);
To your Activity. It only needs to be added to one Activity in the entire app.
Solution 2
My one using 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();
}
}
Then use it in onCreate()
of your main FragmentActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
RateItDialogFragment.show(this, getFragmentManager());
}
Solution 3
Java & Kotlin solution (In-app review API by Google in 2020):
First, in your build.gradle(app)
file, add following dependencies (full setup here)
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'
}
Add this method to your 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.
}
});
}
Call it like any other method:
askRatings();
Kotlin code can be found here
Solution 4
I think what you are trying to do is probably counter-productive.
Making it easy for people to rate apps is generally a good idea, as most people who bother do so because they like the app. It is rumoured that the number of ratings affects your market rating (although I see little evidence of this). Hassling users into rating - through nag screens - is likely to cause people to clear the nag through leaving a bad rating.
Adding the capability to directly rate an app has caused a slight decrease in the numerical ratings for my free version, and a slight increase in my paid app. For the free app, my 4 star ratings increased more than my 5 star ratings, as people who thought my app was good but not great started to rate it as well. Change was about -0.2. For the paid, change was about +0.1. I should remove it from the free version, except I like getting lots of comments.
I put my rating button into a settings (preference) screen, where it does not affect normal operation. It still increased my rating rate by a factor of 4 or 5. I have no doubt that if I tried nagging my users into making a rating, I would get lots of users giving me bad ratings as a protest.
Solution 5
AndroidRate is a library to help you promote your android app by prompting users to rate the app after using it for a few days.
Module 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);
}
}
The default conditions to show rate dialog is as below:
- App is launched more than 10 days later than installation. Change via
AppRate#setInstallDays(byte)
. - App is launched more than 10 times. Change via
AppRate#setLaunchTimes(byte)
. - App is launched more than 1 days after neutral button clicked. Change via
AppRate#setRemindInterval(byte)
. - App is launched X times and X % 1 = 0. Change via
AppRate#setRemindLaunchTimes(byte)
. - App shows neutral dialog (Remind me later) by default. Change via
setShowLaterButton(boolean)
. - To specify the callback when the button is pressed. The same value as the second argument of
DialogInterface.OnClickListener#onClick
will be passed in the argument ofonClickButton
. - Setting
AppRate#setDebug(boolean)
will ensure that the rating request is shown each time the app is launched. This feature is only for development!.
Optional custom event requirements for showing dialog
You can add additional optional requirements for showing dialog. Each requirement can be added/referenced as a unique string. You can set a minimum count for each such event (for e.g. "action_performed" 3 times, "button_clicked" 5 times, etc.)
AppRate.with(this).setMinimumEventCount(String, short);
AppRate.with(this).incrementEventCount(String);
AppRate.with(this).setEventCountValue(String, short);
Clear show dialog flag
When you want to show the dialog again, call AppRate#clearAgreeShowDialog()
.
AppRate.with(this).clearAgreeShowDialog();
When the button presses on
call AppRate#showRateDialog(Activity)
.
AppRate.with(this).showRateDialog(this);
Set custom view
call 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();
Specific theme
You can use a specific theme to inflate the dialog.
AppRate.with(this).setThemeResId(int);
Custom dialog
If you want to use your own dialog labels, override string xml resources on your application.
<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>
Check that Google Play is available
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING) {
}
Related videos on Youtube
Naveen
Updated on July 08, 2022Comments
-
Naveen almost 2 years
I am developing an Android App. In which everything is working right. My app is ready to launch. But there I need to implement one more feature. I need to display a popup that contains
Rate It
andRemind me later
Here if any user rates the app in the market then the popup won't be disappeared. I have searched in Google and found one link. With this, I understand that it's not possible to know. So I need a suggestion for this.
Has anybody faced this situation before? If so, is there any solution or any alternative for this?
-
wtsang02 over 11 yearsSo are you asking for just the Rate it/remind me later or are you asking for how to know if a specific user has rated a Android App?
-
Naveen over 11 yearsi have implemented the popup. but how to know if a user rate the app or not
-
wtsang02 over 11 years-1 I do not see the difference between this question and the one in the link.
-
Naveen over 11 years@wtsang02, May be its true. But see the question. its asked on
Mar 15 2011
. so almost 20 months over. I think some one has solution or alternative for my requirement. that's y i posted here. -
Alexander Savin over 6 yearsYou can use library github.com/Vorlonsoft/AndroidRate (
implementation 'com.vorlonsoft:androidrate:1.0.3'
) -
Khemraj Sharma over 3 yearsBest way is google's in-app review - stackoverflow.com/a/65839952/6891563
-
-
AsafK over 9 yearsThis doesnt support multiple users using the same device.
-
tread about 9 years@AsafK Yes, but multiple users using the same device can be handled by only showing the
apprater
dialog after authentication and changingshared preference
to include the google email address in thekey
. -
narko about 9 yearsGood one! I would just put the editor.commit() before showing the DialogFragment just in case something goes wrong when loading the Dialog.
-
mixel about 9 years@narko Thanks. Updated.
-
Md Imran Choudhury over 8 yearsWhat is "Configs" it's not found when i try.
-
Ruchir Baronia about 8 yearsHi, I have just one question. Why did you make everything static? Thanks Raghav!
-
Gustavo Baiocchi Costa almost 8 years@Md.ImranChoudhury Sorry for the late reply. The configs is a private class of mine that I use for google analytics. You can just remove that statement without a problem!
-
Daniele almost 8 yearsGreat class, really helpful!! you could set the
ShowRateDialog()
method to private to improve performance! -
Zia Ur Rahman almost 8 years@RuchirBaronia, Look at this AppRater.app_launched(this); the function app_launched(this) is only called by writing the name of the class and just call the public static functions and field members ... it is the easiest way and also better in performance than normal class, otherwise you can do it in a simple class, and then create Object of that class and then call it via that Object ... thats it. :)
-
Exception over 7 yearsHi, I am trying your above code. I have put
AppRater.app_launched(this);
inside myonCreate()
of MainActivity. I have also changed the minimum number launches required to 2. But, I am not seeing the dialog after 2 app launch. Can You help me out? Thanks! -
Rohit Mandiwal over 7 yearsyou should either link to original answer or give credit to him. stackoverflow.com/a/6920848/563735
-
KJEjava48 over 7 years@Raghav Sood Does it show the dialog each time the user open the app after 3 days of the launch??
-
akash varlani over 6 years100% true. The same thing happened with my free app too.
-
Alexander Savin over 6 yearsYou can use library github.com/Vorlonsoft/AndroidRate (
implementation 'com.vorlonsoft:androidrate:1.0.3'
) . It's up to date. -
aslamhossin over 6 yearsneed to add this line editor.putLong("launch_count", 0); for restart the counter again other wise user dialog will appears again . For prevent this issue add this in "Remind me later" option.
-
Vivek over 5 yearsBetter use the enum
Context.MODE_PRIVATE
-context.getSharedPreferences("apprater", Context.MODE_PRIVATE);
-
Sai almost 5 yearsNote:It can lead to a memory leak if you use to apply to save shared preference. If you notice carefully in
setPositiveButton
andsetNegativeButton
, it is writing to shared preferences using commit but if you use apply which is async and will keep the reference to the activity until it compleats and right after that it is calling dismiss. Dismiss will try to destroy the fragment, but it can't because the activity is held/used by the shared preference apply process.(I wore this because AndroidStudio will prompt the user to change commit to apply, don't do it unless you use some other logic) -
user1090751 about 4 years@mixel How to modify code to be able to use in Activity and without fragment?
-
user2162130 almost 4 yearsBut this review dialog showing only once.How we can show this in-app review dialog more than once in app?
-
Soufiane ROCHDI almost 4 yearsI followed your explanation and the one given by the library author (in github), but I coudn't get the InAppRating message. I initialized the Lib in MainActivity#onCreate method then I call it in fragement. is there any issue related to fragments ?
-
iDecode almost 4 years@user2162130 Haven't tested that yet, but I think it must be done on purpose by Google to prevent the dialog from opening more than once otherwise it will be overwhelming for the users if developers keep on asking for review.
-
user2162130 almost 4 yearsHi I have found the solution, we can test app by using internal App Sharing of google, where we can upload an apk to test In-app rating dialog. After uploading we can test app it will show In-app rating dialog every time according to your condition which you have done in app.
-
Michael Hathi almost 4 yearsYou'll have to upload the apk to at least internal app sharing or internal testing track in order to see this prompt. developer.android.com/guide/playcore/in-app-review/test
-
Soufiane ROCHDI over 3 yearsThank you @Michael it worked. i didn't pay attention to testing part where it's explained in the official documentation.
-
iDecode over 3 years@AG-Developer Didn't check it yet, but I'm sure it must be API >= 21
-
Luc Bloom over 3 yearsWhen calling mContext.startActivity, please catch ActivityNotFoundException and fall back to an URL like Uri.parse("play.google.com/store/apps/details?id=" + ctx.getPackageName()) for devices that don't have the Goolge Play Store installed (e.g. Chinese)
-
Shriram Panchal over 3 yearsOne drawback of this dialog is that it is modal less dialog, if user unfortunately clicks on other area of screen it will leave the universe and entire efforts will be in water
-
iDecode over 3 years@ShriramPanchal You can create a feature request for it.
-
Khemraj Sharma over 3 yearsBest way is now Google's In-app review - stackoverflow.com/a/65839952/6891563
-
Lukas Niessen over 2 yearsRather use
BuildConfig.APPLICATION_ID
instead of the fieldAPP_PNAME
-
Sergio over 2 yearsI would also include in the button 1 listener the lines: if (editor != null) { editor.putBoolean("dontshowagain", true); editor.commit(); }
-
JPM over 2 yearsAs always google takes something and over complicates it and documentation isn't complete. Also the use case has only one use but others may want to know why request failed and act upon it. API is worthless junk.
-
JPM over 2 yearsYeah doesn't work in Production or Debug mode for me. App is already in store so no need. Not sure why its not working