Force update of an Android app when a new version is available
Asked Answered
C

23

163

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?

Coppinger answered 8/10, 2013 at 9:44 Comment(3)
This open source GitHub project (MAHAndroidUpdater)is completely providing this functionality. Try it, Very simple. github.com/hummatli/MAHAndroidUpdaterReitareiter
The best practice is to support old versions - especially for Android devices, because a forced update block on an Android app sends users to Google Play app, which is notorious for caching the old version of app pages for hours with no refresh capability except to force quit the app - a big problem most don't know about unless you have to answer 1,000 phone calls related to this on release day.Sarchet
Version your APIs.Sarchet
A
140

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.

Arianearianie answered 6/12, 2013 at 6:18 Comment(5)
Would you show popup everytime the app starts and recommendUpgrade is true? (from UX point of view) Or just show the popup once and don't show again if user declines to upgrade.Hawker
For recommended upgrade, I think you shouldn't show again if user declined. You could also show it "once every n times that the user opened the app". You could decide the n value yourself and implement that.Arianearianie
a better solution imo is to pass the version of the app systematically in the header of all API calls, and then have the API return a specific status code if it detects the version is obsolete. and then handle it inside the app. this is better than having to call yet another dedicated API for this check, and having to figure out exactly when/where this API call should done inside the app/service.Morgen
@RaphaelC This really depends on your server side implementation. Its also not perfect to add a filter that checks the version on all API's in some situations.Apocalyptic
@SepGH things have changed since, and Android now offers an API which you can use to force the user to upgrade and block him from continuing using the app if he doesn't upgrade to a minimum version: developer.android.com/guide/app-bundle/in-app-updatesMorgen
D
61

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();
    }
Direct answered 5/10, 2015 at 6:52 Comment(14)
I guess this would require the use to the add the external library JSoup?Tilly
Yes, but that would be for getting the html div page. I meant to say, that you may not need to use any third party library to achieve this functionality, if you can scrape that html element without JSoup, still it would workDirect
what if they change itemprop value??Symptomatology
If they change the itemprop value, then it'd affect my apps too, I'd edit my answer to support that immediately, so no worry till then :)Direct
Nice setCancelable(false)Shack
@AshuKingSharma. can u pls tell what is background.start(); in builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()Battle
@sunily: background is a thread which is used to run the activity, I am calling this function in splash and using background thread variable to run main activity, if user don't want to update, it is calledDirect
i am getting this error java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String org.jsoup.nodes.Element.text()' on a null object referenceHamal
at this line latestVersion = doc.getElementsByAttributeValue ("itemprop","softwareVersion").first().text();Hamal
@benarjeebojja: i am using org.jsoup:soup:1.7.3 and use it in async task, and this error indicates that Jsoup is unable to get the element from playstore url, try again, it should work, checked, working perfectly for me and tell if you still get the errorDirect
@Direct This method will work no more, since play store html is updatedFantail
@SibinDavis: thanks for bringing this up, have updated the link and verified, this would work now :). Just change latestVersion = doc.getElementsByClass("htlgb").get(6).text(); in the above code, and it is ready to use :). In future also, if something comes up, please let me know, as I had said before, I'd keep updating. Thanks :)Direct
As Sibin Davis said this work around will fail if the html page is updated Please tell me if you guys have any other ways to doBrame
If the Google Play cache is not up to date then the cache will return the version numbers that will not be the same as the latest version you have on the app store and hence cannot force the update until the Play Cache is updated..Goulder
I
56

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.

Idaidae answered 8/10, 2013 at 9:56 Comment(9)
@Coppinger if this or any answer has solved your question please consider accepting it by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. There is no obligation to do this.Lovelorn
The answer is subjective to how many software vendors YOU KNOW OF in existence. Can you quantify that?Stettin
Is it possible to get current app version from app store or play store? or whether I need to keep latest app version in my server? Because right now I have service call in my server to return latest app version, but difficulty is each time need to update the server while publishing the app. Hence is it possible to get current version number from respective stores?Muscovado
Supercell only supports the latest version of their games. After they've pushed a new version to Google Play, any older client trying to connect will get a "need to update" response from the server and see the connection closed. They're doing this multiple times every year. So unless you don't want to count a "game company" as "software vendor", now you know one :) Considering they're still making a couple of million dollars every day, apparently this terrible user experience is not a show stopper.Birdie
@Subha Yes, that's possible. But there's no official API for it, so you'd need to scrape the web pages. Which also means that it may break if the web page changes. I did it in a third party app that I wrote and posted the rather simple code as answer here. Currently, the code will work for both Play and iTunes pages. In a production environment though, it may be better to look for a solution that'd automatigally update the latest app version on the server, instead of having to rely on the format of pages at Google or Apple?Birdie
In a mulitplayer game I have to force users to update to the latest version in order to avoid desynced clients.Insusceptible
I agree. Furthermore, users can still use your app if they are offline and won't get this information until they have access to the network and only on the callback of the api call for checking this. Finally, if you have many activities, intent services, and more, where exactly are you gonna do this check? on resume of all activities? what happens if you have an intent service? it will still be available and will continue to handle intents until your users open the app. in short, so many edge cases, it's a bad idea to do this unless your app is just an interface for API calls.Morgen
> What happens if the user can't update or doesn't want to at that time? If the user can't update because of no internet connection, then he can't be blocked either, and the app cannot stop working for offline functions. If the user has an internet connection, then he can update.Arvo
Supporting multiple versions of the API and implementing forced upgrades are not mutually exclusive. They may not even be related.Hypochondriac
A
42

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

Amidst answered 8/5, 2019 at 7:36 Comment(0)
S
37

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://mcmap.net/q/151736/-prompt-android-app-user-to-update-app-if-current-version-lt-gt-market-version

Seldun answered 28/6, 2019 at 14:16 Comment(4)
This is the best answer!Curnin
This feature actually relies on the Play cache being up to date when user launches your app i.e If the version number for your app in the cache is not the same as the version number of your latest deployment on Playstore then it wont prompt the user..Goulder
Any option. to customize the layout?Palaeogene
IMMEDIATE mode still allows user to X out of that screen :(Adaptive
P
16

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.

Peppy answered 31/1, 2014 at 16:31 Comment(0)
B
14

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

Blackfish answered 9/11, 2018 at 14:17 Comment(4)
Also see: android-developers.googleblog.com/2018/11/…Parent
Is this api now available?Permeability
I google it and found this developer.android.com/guide/app-bundle/in-app-updatesBlackfish
This feature actually relies on the Play cache being up to date when user launches your app i.e If the version number for your app in the cache is not the same as the version number of your latest deployment on Playstore then it wont prompt the user..Goulder
W
11

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.

Wozniak answered 13/12, 2016 at 23:39 Comment(1)
This is a very good option. By specifying a subset of "disabled" versions, you can quickly protect yourself, should an app have security issues or major performance issues. It allows you to continue supporting every version but ban specific version when a need arises.Vaquero
O
4

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>

Oneness answered 6/10, 2017 at 9:43 Comment(0)
D
3

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://mcmap.net/q/151737/-android-version-code-for-app-updating

Disposure answered 3/10, 2019 at 5:25 Comment(0)
O
3

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...
Overuse answered 30/12, 2020 at 7:25 Comment(0)
S
2

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.

Severen answered 26/5, 2015 at 10:22 Comment(0)
P
1

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://mcmap.net/q/151735/-android-in-app-version-check 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.

Protoactinium answered 13/2, 2016 at 19:24 Comment(0)
K
1

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.

Kindig answered 29/1, 2019 at 9:9 Comment(0)
E
1

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

Ecliptic answered 21/6, 2019 at 11:15 Comment(0)
B
1

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

Brena answered 21/7, 2019 at 13:15 Comment(0)
D
1

You can achieve the same using the answers mentioned here, if you are looking for an easy to integrate built in solution. You can use App Upgrade https://appupgrade.dev/ service to force update your mobile apps.

  • Create new version entry for your app version that you want to update in the app upgrade service and select whether you want to force it or just want to let users know that new version is available.

App Upgrade

  • Integrate your app with App Upgrade using available SDK. Official SDK are available for React Native, Flutter, Expo, Android and iOS(Swift). The SDK will take care of the rest. Whenever you want to force upgrade a version just create a version entry in app upgrade dashboard.

App Upgrade Popup

  • You can also integrate using API. Just call the appupgrade api from your app with the required details such as your app version, platform, environment and app name.
  • The API will return you the details.. that this app needs to be updated or not.
  • Based on the response you can show popup in your app.You can call this API when app starts or periodically to check for the update. You can even provide a custom message. API response:

App Upgrade API Response

See the response has force update true. So handle in the app by showing popup.

App Upgrade Popup

You can find the complete user documentation here. https://appupgrade.dev/docs

Thanks.

Durkin answered 2/4, 2022 at 10:0 Comment(0)
I
1

In my opinion, the simplest way is to create an API, which contains the latest version of your application. Then in the application, create a dialog and check if the version of the application on the human machine is equal to the version on the API. If not, display the Dialog and ask the user to update the app on the store. This Dialog will navigate to your app dashboard on the store

Inainability answered 18/10, 2022 at 10:25 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Fetus
G
0

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.

Gypsie answered 6/3, 2016 at 7:49 Comment(0)
N
0

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.

Nurseryman answered 12/10, 2016 at 18:45 Comment(0)
T
0

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

Tredecillion answered 21/6, 2019 at 10:38 Comment(0)
G
0

For those looking for a quick and free solution, I would recommend Semaphr. Integration should not take more than 10 minutes and you can control everything from the dashboard:

  • what message to show
  • which versions should be covered
  • schedule your upgrade
  • see live app versions statistics
Germany answered 2/8, 2023 at 11:7 Comment(0)
I
-2
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;
        }          
      }
  }
}
Ipoh answered 10/9, 2020 at 4:41 Comment(1)
This is Javascript code that compares two versions. The question is about forcing users to update their apps.Parthenopaeus

© 2022 - 2024 — McMap. All rights reserved.