Forced Update of Mobile Apps

In this article, I’m going to describe how you can force users to upgrade your mobile app to the latest version — and when and why you would want to do that.

Use cases

  1. Breaking API changes

  2. If you control both the API and the client app(s), then maintaining access to old API versions might not be necessary. In this case, you could update the API and the client app(s) in step. (This makes most sense in the case of enterprise apps. It likely wouldn’t be an acceptable solution for apps released to the public.)

  3. Security issues

  4. A security vulnerability is probably the worst case scenario for any software developer. In the case of a vulnerability in a mobile app, you’ll want to stop use of affected app version(s) as soon as possible.

  5. Bugs

  6. Pretty much anyone who’s ever published an app to the Play Store, the App Store, or anywhere else will have found themselves, sooner or later, having to rush out an update to fix a bug. The type of feature described in this article would be most applicable to critical bugs.

Taking action

Once you find yourself facing one of the above situations, you’ll have to answer the question: How do I make sure people upgrade to the fixed version?

One possible answer is to have “forced update”, or blacklist, functionality built into your app. Obviously, this feature has to be implemented before you release any critical bugs — so it’s best to think of it at the start of a project. There are numerous ways to implement this. I’ll describe a method making use of Firebase Remote Config, but you could also read values from your own API, for example.

Before we start, there are a few prerequisites that I won’t cover in this article:

  • You need to have created a Firebase project (or have an existing project).

  • Google Analytics must be enabled for your Firebase project.

  • In project settings, your app needs to have been added to the “Your apps” section.

  • Your app must have been configured to use Firebase services (google-services.json (Android) or GoogleService-Info.plist (iOS) added; Google Analytics dependency added).

Note: I’ll use Android in this tutorial, but the steps for iOS are very similar.

Once the prerequisites have been met, we’re ready to add a minimum required version number to Firebase Remote Config. Add a parameter called “minimum_version” or similar with whatever value suits you. Note: I’m using the version code (which is analogous to the build number in iOS), as this is guaranteed to increase with each release, whereas the version name can remain the same in subsequent releases.

Firebase Remote Config

The next step is to add the code to read this value in the app.


Step 1: Initialise Firebase Remote Config in your activity.

private FirebaseRemoteConfig mRemoteConfig;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final FirebaseRemoteConfigSettings settings =
        new FirebaseRemoteConfigSettings.Builder()
            .setMinimumFetchIntervalInSeconds(3600)
            .build();
    mRemoteConfig = FirebaseRemoteConfig.getInstance();
    mRemoteConfig.setConfigSettingsAsync(settings);
}

Step 2: When the activity starts, start the version check.

@Override
protected void onResume() {
    super.onResume();
    mRemoteConfig.fetchAndActivate()
        .addOnCompleteListener(this, task -> {
            if (task.isSuccessful()) {
                checkVersion();
            } else {
                // Fetching Remote Config failed.
            }
        });
}

You’ll have to make a decision about what to do if fetching Remote Config fails. You might decide to allow the app to run normally; or, if it’s critical that users don’t use old app versions, you could block the app from running (see next step).

Step 3: Perform the version check.

private void checkVersion() {
    final long minimumVersion =
        mRemoteConfig.getLong("minimum_version");
    if (BuildConfig.VERSION_CODE < minimumVersion) {
        new AlertDialog.Builder(MainActivity.this)
            .setTitle("Update required")
            .setMessage("To continue using this app, "
                + "you must update to a later version.")
            .setPositiveButton("Update",
                (dialog, which) -> openPlayStorePage())
            .create()
            .show();
    }
}

Step 4: Redirect the user to the Play Store (or take whatever action is appropriate for your app).

private void openPlayStorePage() {
    final String packageName = getPackageName();
    try {
        startActivity(new Intent(Intent.ACTION_VIEW,
            Uri.parse("market://details?id=" + packageName)));
    } catch (ActivityNotFoundException e) {
        startActivity(new Intent(Intent.ACTION_VIEW,
            Uri.parse("https://play.google.com/store/apps/details?id=" + packageName)));
    }
}

Variations

As I said earlier, this could be implemented on iOS very similarly. Sticking with Android, however, it’s worth taking note that Google Play now has a built-in solution for these types of update requirements, in a feature called “in-app updates”. If your app is Android only, then I’d suggest seeing if this meets your requirements before embarking upon a custom solution such as the one described above.

https://developer.android.com/guide/playcore/in-app-updates

Another variation on this idea is blacklisting, in which, rather than having a required minimum version, you can blacklist specific app versions. For example, you could blacklist v2.2 (perhaps it introduced a critical bug or corrupts user data) whilst allowing users to continue using v2.1.

Wrapping up

I hope this article might inspire you to consider implementing this sort of feature in your apps. You might end up needing to use it rarely, but, when you do find yourself having to deal with crash reports from unhappy users, you might be very glad you thought about this first!

Previous
Previous

Bug Reporting Is a Science

Next
Next

Test Like a Mother