32

In my Android app, I want to prompt the user at some point of time to rate the app in Android market.

Having searched for an approach, I've found some code on this website. This code seems to work very well.

But unfortunately, this code seems to raise a "Forced Close" error message when Android market is not installed on the user's phone. Is there any way to check if Android market is installed and, if not, don't try to execute the code?

The line which raises the error is probably this one as it cannot parse the URI:

mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APP_PNAME)));

And, by the way, are there any other things which could be improved in that code?

Edit:

A few years later, I've put all the code into a small library project: AppRater on GitHub

caw
  • 30,999
  • 61
  • 181
  • 291
  • is it possible to test your library before the release of the app on the playstore? Or it must be present on the store for the popup to be shown? – Stack Diego Jan 20 '15 at 22:04
  • 1
    @StackDiego Just get the latest JAR from the GitHub project and call `demo()` instead of `show()` :) Thanks for the feedback! – caw Jan 21 '15 at 00:56
  • Thank you, i'm going to try right now – Stack Diego Jan 22 '15 at 08:58

10 Answers10

36

Here's all the code you need, (a conglomeration of Kurt's answer and inferred information, plus the link and the question):

/* This code assumes you are inside an activity */
final Uri uri = Uri.parse("market://details?id=" + getApplicationContext().getPackageName());
final Intent rateAppIntent = new Intent(Intent.ACTION_VIEW, uri);

if (getPackageManager().queryIntentActivities(rateAppIntent, 0).size() > 0)
{
    startActivity(rateAppIntent);
}
else
{
    /* handle your error case: the device has no way to handle market urls */
}
xbakesx
  • 13,202
  • 6
  • 48
  • 76
14

You can always call getInstalledPackages() from the PackageManager class and check to make sure the market class is installed. You could also use queryIntentActivities() to make sure that the Intent you construct will be able to be handled by something, even if it's not the market application. This is probably the best thing to do actually because its the most flexible and robust.

Kurtis Nusbaum
  • 30,445
  • 13
  • 78
  • 102
9

You could also use RateMeMaybe: https://github.com/Kopfgeldjaeger/RateMeMaybe

It gives you quite some options to configure (minimum of days/launches until first prompt, minimum of days/launches until each next prompt if user chooses "not now", dialog title, message etc.). It is also easy to use.

Example usage from README:

RateMeMaybe rmm = new RateMeMaybe(this);
rmm.setPromptMinimums(10, 14, 10, 30);
rmm.setDialogMessage("You really seem to like this app, "
                +"since you have already used it %totalLaunchCount% times! "
                +"It would be great if you took a moment to rate it.");
rmm.setDialogTitle("Rate this app");
rmm.setPositiveBtn("Yeeha!");
rmm.run();
nspo
  • 1,488
  • 16
  • 21
  • 1
    Let's say if i execute code in onCreate of my first activity then will it ever display dialog to user ? Because everytime i calling method of RateMeMaybe that display dialog after 14 days. Right? – keen Apr 28 '14 at 12:41
6

First you need to count the application used times;

SharedPreferences preferences = getSharedPreferences("progress", MODE_PRIVATE);
int appUsedCount = preferences.getInt("appUsedCount",0);
appUsedCount++;
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("appUsedCount", appUsedCount);
editor.apply();

if (appUsedCount==10 || appUsedCount==50 || appUsedCount==100 || appUsedCount==200 || appUsedCount==300){
    AskForRating(appUsedCount);
} else {
    finish();
}

Than you can prompt like this;

private void AskForRating(int _appUsedCount){

    AlertDialog.Builder alert = new AlertDialog.Builder(this);
    alert.setTitle("Please Rate Us");
    alert.setIcon(R.drawable.book);
    alert.setMessage("Thanks for using the application. If you like YOUR APP NAME please rate us! Your feedback is important for us!");
    alert.setPositiveButton("Rate it",new Dialog.OnClickListener(){
        public void onClick(DialogInterface dialog, int whichButton){
            String url = "https://play.google.com/store/apps/details?id=YOUR PACKAGE NAME";
            Intent i = new Intent(Intent.ACTION_VIEW);
            i.setData(Uri.parse(url));
            startActivity(i);
        }
    });
    alert.setNegativeButton("Not now", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            finish();
        }
    });
    alert.show();
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
DiRiNoiD
  • 1,281
  • 2
  • 18
  • 24
  • The difference here is that it will take you to the website through a browser instead of using the play store app. You should first check that using the play store app is not possible then use the browser to go to the website. – xxx Sep 05 '16 at 15:45
1

Not all android devices use the app market. Kindle and Nook have their own marketplace so the need for code to check whether or not the market exists is a good one. Although there should be a way to send the rating to the correct marketplace, no matter which one it is. Something to look into.

Kapt Kaos
  • 21
  • 3
  • 1
    This isn't really an issue anyways, considering that Nook and Amazon markets have a submission process where these links are always checked. You will never get an app accepted to be published in either of those markets with a rate link to google, so the force close wouldn't be an issue, you would have to redo the rate code specific for the market. – Rev Tyler Jul 08 '13 at 02:47
1

This simple code will achieve what you want, no need for external libraries or anything fancy. Just put it on the OnCreate event on your main activity. The variable RunEvery will determine how often the rate message will appear. In the example it's set to 10.

// Count times app has been opened, display rating message after number of times  
// By Rafael Duval   
    try {

        // Get the app's shared preferences
        SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(this);

        // Get the value for the run counter
        int counter = app_preferences.getInt("counter", 0);

        // Do every x times
        int RunEvery = 10;

        if(counter != 0  && counter % RunEvery == 0 )
        {
            //Toast.makeText(this, "This app has been started " + counter + " times.", Toast.LENGTH_SHORT).show();

           AlertDialog.Builder alert = new AlertDialog.Builder(
                     MyActivity.this);
                   alert.setTitle("Please rate");
                   alert.setIcon(R.drawable.ic_launcher); //app icon here
                   alert.setMessage("Thanks for using this free app. Please take a moment to rate it.");

                   alert.setPositiveButton("Cancel",
                     new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog,
                        int whichButton) {                            
                          //Do nothing
                      }   
                     });

                   alert.setNegativeButton("Rate it",
                     new DialogInterface.OnClickListener() {

                      public void onClick(DialogInterface dialog, int which) {   

                           final String appName = getApplicationContext().getPackageName();
                           try {
                            startActivity(new Intent(Intent.ACTION_VIEW,
                              Uri.parse("market://details?id="
                                + appName)));
                           } catch (android.content.ActivityNotFoundException anfe) {
                            startActivity(new Intent(
                              Intent.ACTION_VIEW,
                              Uri.parse("http://play.google.com/store/apps/details?id="
                                + appName)));
                           }   

                      }
                     });
                   alert.show();            
        }


        // Increment the counter
        SharedPreferences.Editor editor = app_preferences.edit();
        editor.putInt("counter", ++counter);
        editor.commit(); // Very important          

    } catch (Exception e) {
        //Do nothing, don't run but don't break
    }           
Yo Mismo
  • 11
  • 3
0

When i use "market://details?id=" + getApplicationContext().getPackageName() it opens mobogenie market on me, so i prefer to use https://play.google.com/store/apps/details?id=" + getApplicationContext().getPackageName()

Jemshit
  • 9,501
  • 5
  • 69
  • 106
  • This just means that your alternative marketplace says it can handle `market://` URLs, too. And you probably chose this app as the default on your phone then. – caw Jul 19 '14 at 21:46
0

use this code

Uri uri = Uri.parse("market://details?id=" + context.getPackageName());
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
// To count with Play market backstack, After pressing back button, 
// to taken back to our application, we need to add following flags to intent. 
goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
                Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
try {
    startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
    startActivity(new Intent(Intent.ACTION_VIEW,
            Uri.parse("http://play.google.com/store/apps/details?id=" + context.getPackageName())));
}
Pankaj Talaviya
  • 3,328
  • 28
  • 31
0

If the application was downloaded through Android Market, users will have Android Market installed on the phone, so I really don't see this as a problem. It seems very weird...

You can use the following to launch Android Market on your application's page, it's a bit more automated:

Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("market://details?id=" + getPackageName()));
startActivity(i);
Michell Bak
  • 13,182
  • 11
  • 64
  • 121
  • The code you posted works, but the code shown in the link above is shorter - just a single line to start the intent. And: Of course, there is a possibility that users don't have the Android market app: They download my app through Android market and then (at some time) remove Android market app from their phone ;) – caw Nov 06 '11 at 23:45
  • Why on earth would they ever want to do that? It seems incredibly stupid. Definitely not something you as a developer should care about. But if you insist, you can do what Kurtis is suggesting. Check if the application is installed. You can also do the following: http://stackoverflow.com/questions/4439043/what-is-the-package-name-of-the-android-market-or-google-apps and check if it's returning an application. – Michell Bak Nov 06 '11 at 23:49
  • 1
    Thank you. It may be "stupid" but possible, nevertheless. The method getPackageName() is a nice way to avoid hard-coding the package name. But since the class (see link) is in an external class I cannot use it. – caw Nov 08 '11 at 13:19
-2

There are other options now. Here is a comparison which can help you to choose which one to use.

https://polljoy.com/blog/irate-vs-appirater-open-source-rating-prompts-alternatives

enter image description here

Kilogen9
  • 173
  • 1
  • 7