[android] Force update of an Android app when a new version is available

I have an app in Google Play Store. When an update version is available, the older version will become unusable – that is, if users do not update the app, they do not enter in the app. How can I force users to update the app when a new version becomes available?

This question is related to android

The answer is


var activeVersion = "3.9.2";

var currentVersion = "3.9.1";

var activeVersionArr = activeVersion.split("."); var currentVersionArr = currentVersion.split(".");

var compareArray =JSON.stringify(activeVersionArr)==JSON.stringify(currentVersionArr);

if(compareArray){ return false; }

if(!compareArray){ for(var i=0;i<activeVersionArr.length;i++){
if(activeVersionArr[i]!==currentVersionArr[i]){
if(activeVersionArr[i] > currentVersionArr[i]){ return true; }else{ return false; }
} } }


check version code of local and play store apk

try {
        versionChecker VersionChecker = new versionChecker();
        String versionUpdated = VersionChecker.execute().get().toString();
        Log.i("version code is", versionUpdated);


        PackageInfo packageInfo = null;
        try {
            packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        int version_code = packageInfo.versionCode;
        String version_name = packageInfo.versionName;
        Log.i("updated version code", String.valueOf(version_code) + "  " + version_name);
        if (version_name != versionUpdated) {
            String packageName = getApplicationContext().getPackageName();//
            UpdateMeeDialog updateMeeDialog = new UpdateMeeDialog();
            updateMeeDialog.showDialogAddRoute(MainActivity.this, packageName);
            Toast.makeText(getApplicationContext(), "please updated", Toast.LENGTH_LONG).show();
        }
    } catch (Exception e) {
        e.getStackTrace();
    }

implement class for version check

class versionChecker extends AsyncTask<String, String, String> {
String newVersion;

@Override
protected String doInBackground(String... params) {

    try {
        newVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=+YOR_PACKAGE_NAME+&hl=en")
                .timeout(30000)
                .userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
                .referrer("http://www.google.com")
                .get()
                .select("div[itemprop=softwareVersion]")
                .first()
                .ownText();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return newVersion;
}
}

dialob box for update

public class UpdateMeeDialog {

ActivityManager am;
TextView rootName;
Context context;
Dialog dialog;
String key1,schoolId;
public void showDialogAddRoute(Activity activity, final String packageName){
    context=activity;
    dialog = new Dialog(context);

    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setCancelable(false);
    dialog.setContentView(R.layout.dialog_update);
    am = (ActivityManager)activity.getSystemService(Context.ACTIVITY_SERVICE);

    Button cancelDialogue=(Button)dialog.findViewById(R.id.buttonUpdate);
    Log.i("package name",packageName);
    cancelDialogue.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent=new Intent(Intent.ACTION_VIEW);                
    intent.setData(Uri.parse("https://play.google.com/store/apps/details?
    id="+packageName+"&hl=en"));
            context.startActivity(intent);
        }
    });
    dialog.show();
}
}

dialog layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d4e9f2">


<TextView
    android:layout_width="match_parent"
    android:layout_height="40dp"

    android:text="Please Update First..!!"
    android:textSize="20dp"
    android:textColor="#46a5df"
    android:textAlignment="center"
    android:layout_marginTop="50dp"
    android:id="@+id/textMessage"
    />
<LinearLayout
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:weightSum="1"
    android:layout_marginTop="50dp"
    android:layout_below="@+id/textMessage"
    android:layout_height="50dp">

    <Button
        android:id="@+id/buttonUpdate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Update"
        android:background="#67C6F1"
        android:textAlignment="center" />
</LinearLayout>


Google introduced In-app updates lib, (https://developer.android.com/guide/app-bundle/in-app-updates) it works on Lollipop+ and gives you the ability to ask the user for an update with a nice dialog (FLEXIBLE) or with mandatory full-screen message (IMMEDIATE).

You need to implement the latter. Here is how it will look like: enter image description here

I covered all the code in this answer: https://stackoverflow.com/a/56808529/5502121


I agree with Scott Helme's point in another answer here. But in some extreme situations (security issues, API breaking changes...) where you absolutely need the users to update to continue using the app, you could provide a simple versioning API. The API would look like this:

versionCheck API:

Request parameters:

  • int appVersion

Response

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

When your app starts, you could call this API that pass in the current app version, and check the response of the versioning API call.

If forceUpgrade is true, show a popup dialog with options to either let user quit the app, or go to Google Play Store to upgrade the app.

Else if recommendUpgrade is true, show the pop-up dialog with options to update or to continue using the app.

Even with this forced upgrade ability in place, you should continue to support older versions, unless absolutely needed.


you can do this by doing a match between a version number that is kept on app in a variable and similarly the current app version is kept on server side and each time user opens the app the first request should be send to check that if it founds matching do nothing simply let the user use your app otherwise fire an intent to the google playstore or open a webview window to your app(window.open("https://play.google.com/store/apps/details?id=package_name", '_system', 'location=yes');) and there they will automatically have the button asking for update that's what google playstore does for you if you dont have automatic updates on.


You can use the Play Core Library In-app updates to tackle this. You can check for update availability and install them if available seamlessly.

In-app updates are not compatible with apps that use APK expansion files (.obb files). You can either go for flexible downloads or immediate updates which Google Play takes care of downloading and installing the update for you.

dependencies {
    implementation 'com.google.android.play:core:1.5.0'
    ...
}

Refer this answer https://stackoverflow.com/a/58212818/7579041


It is better to define our own process to for upgrade.

  1. Create a web service which gives latest version for app (ios,android) from our server.
  2. Or Any web service that you used in app (e.g Login) will return latest app version from server.
  3. Once app will get version from #1 or 2. App will cross check it with local/cuurent appversion. if there is difference then we can show alert as follows,

Android & iOS : If latest app version available then it will show alert as “Latest version available with more features, To upgrade click on upgrade button” (Alert with “Upgarde” and “No. Thanks” button.) Then app will redirect to playstore/Appstore and it will open latest version.

 --- we can do upgrade compulsory or optionally.

Before Upgrade process please make sure that you handled proper db migration process if there is any db schema change.


try this: First you need to make a request call to the playstore link, fetch current version from there and then compare it with your current version.

String currentVersion, latestVersion;
Dialog dialog;
private void getCurrentVersion(){
 PackageManager pm = this.getPackageManager();
        PackageInfo pInfo = null;

        try {
            pInfo =  pm.getPackageInfo(this.getPackageName(),0);

        } catch (PackageManager.NameNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        currentVersion = pInfo.versionName;

   new GetLatestVersion().execute();

}

private class GetLatestVersion extends AsyncTask<String, String, JSONObject> {

        private ProgressDialog progressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected JSONObject doInBackground(String... params) {
            try {
//It retrieves the latest version by scraping the content of current version from play store at runtime
                Document doc = Jsoup.connect(urlOfAppFromPlayStore).get();
                latestVersion = doc.getElementsByClass("htlgb").get(6).text();

            }catch (Exception e){
                e.printStackTrace();

            }

            return new JSONObject();
        }

        @Override
        protected void onPostExecute(JSONObject jsonObject) {
            if(latestVersion!=null) {
                if (!currentVersion.equalsIgnoreCase(latestVersion)){
                   if(!isFinishing()){ //This would help to prevent Error : BinderProxy@45d459c0 is not valid; is your activity running? error
                    showUpdateDialog();
                    }
                }
            }
            else
                background.start();
            super.onPostExecute(jsonObject);
        }
    }

private void showUpdateDialog(){
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("A New Update is Available");
        builder.setPositiveButton("Update", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse
                        ("market://details?id=yourAppPackageName")));
                dialog.dismiss();
            }
        });

        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                background.start();
            }
        });

        builder.setCancelable(false);
        dialog = builder.show();
    }

For forcing the app user to update if an update is available in the market, you should first check the app version on the market and compare it with the version of the app on the device. If they are different, it may be an update available. In this post I wrote down the code for getting the current version of market and current version on the device and compare them together. I also showed how to show the update dialog and redirect the user to the update page. Please visit this link: https://stackoverflow.com/a/33925032/5475941 Just make sure that in the dialog you only show the user update button and don't show him the cancel button. In this case he will be forced to update, before he can use the app.


Officially google provide an Android API for this.

The API is currently being tested with a handful of partners, and will become available to all developers soon.

Update API is available now - https://developer.android.com/guide/app-bundle/in-app-updates


Solution from Google team

Starting from Android 5.0 that's easily achievable through the new Google Play In App updates mechanism. The requirements are to have Play Core library of version 1.5.0+ and use App Bundles idstribution instead of apks.

The library provides you 2 different ways to notify the users about the update:

  1. Flexible, when users can continue using the app while it is being updated in the background.

  2. Immediate - blocking screen that doesn't allow a user to enter the app until they update it.

There are next steps to implement it:

  1. Check for update availability
  2. Start an update
  3. Get a callback for update status
  4. Handle the update

All of these steps implementations are described in details on the official site: https://developer.android.com/guide/app-bundle/in-app-updates


It is good idea to use remote config for app version and always check in launch activity is current app version is same as remote version or not if not force for update from app store..

Simple logic happy coding..

https://firebase.google.com/docs/remote-config/android


Well, there could be many solutions to this problem like scraping the version code from App Page (Google Play App page), etc.

But I am going to show you the ultimate solution that won't cost a penny and will work like magic.

  1. Just save the latest Version code of your app on Firebase Remote
    Config panel
  2. Fetch that version code value whenever the app is opened
  3. Compare it with the current version code of the app, which you can get by the following code

    private int getCurrentVersionCode() {
    try {
        return getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
    } catch (NameNotFoundException e) {
        e.printStackTrace();
    }
    return -1;
    

    }

If the fetched version code is greater than the current version, show an AlertDialog asking to update the app. Otherwise, the app is already updated.

So, whenever you roll out the new version, you need to put that new version code in Firebase Remote config panel

You can read the whole tutorial on how to force users to update the app using Firebase Remote Config


I used a simple approach to make this work:

  1. Create Firebase database
  2. Add your latest version
  3. If the version is different than the installed version, show the popup of installing the update. It works perfectly for me...

Google released In-App Updates for the Play Core library.

I implemented a lightweight library to easily implement in-app updates. You can find to the following link an example about how to force the user to perform the update.

https://github.com/dnKaratzas/android-inapp-update#forced-updates


What should definitely be mentioned here is the soon-to-be released In-app Updates API.

You'll have two options with this API; the first is a full-screen experience for critical updates when you expect the user to wait for the update to be applied immediately. The second option is a flexible update, which means the user can keep using the app while the update is downloaded. You can completely customize the update flow so it feels like part of your app.


I highly recommend checking out Firebase's Remote Config functionality for this.

I implemented it using a parameter - app_version_enabled - with a condition "Disabled Android Versions" that looks like this:

applies if App ID == com.example.myapp and App version regular expression ^(5.6.1|5.4.2) 

Default for the parameter is "true", but Disabled Android Versions has a value of false. In my regex for Disabled Android Versions, you can add more disabled versions simply with another |{version name} inside those parentheses.

Then I just check if the configuration says the version is enabled or not -- I have an activity that I launch that forces the user to upgrade. I check in the only two places the app can be launched from externally (my default launcher activity and an intent-handling activity). Since Remote Config works on a cache basis, it won't immediately capture "disabled" versions of the app if the requisite time hasn't passed for the cache to be invalidated, but that is at most 12 hours if you're going by their recommended cache expiration value.


You shouldn't stop supporting an older version as soon as a new version comes out. This will result in a terrible user experience. I don't know of any software vendor in existence that does this, for good reason.

What happens if the user can't update or doesn't want to at that time? They simply can't use your app, which is bad.

Google don't provide any option for version tracking like that so you would have to roll your own. A simple web service to return the current live version that your app can check would be sufficient. You can then update the version and the app will know it is outdated. I would only recommend using this to let your users know there is an update more quickly than depending on Google Play. It should not really be used to prevent the app from working, just to prompt the user to update.


Scott and Michael's answers are correct. Host a service that provides a min version number you support and compare that to the installed version. You should hopefully never need to use this, but it's a life saver if some version is out there you absolutely must kill due to some serious flaw.

I just wanted to add the code for what to do next. Here is how you then launch the Google Play Intent and take them to your new version in the store after prompting the user that they must upgrade.

public class UpgradeActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_upgrade);
        final String appName = "com.appname";
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

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

            }
        });
    }
}

You should re-consider your design if you have to force upgrades on each release.


You can notify your users that there is a new version of the current app available to update. Also, if this condition is true, you can block login in the app.

Please see if this provides you the solution.