If you're an Android user, you have experienced being kicked out of your current application just for an update. Well, Google has heard the complaints and introduced the general release of In-App Updates at Google IO 2019. This new feature will allow users to continue to use an app and install updates when they are ready instead of being forced out of their app. Follow along to learn how to set up in-app updates!

Sample Application

For a closer look into In-App Updates, take a look at this sample application. This sample will include all of the features mentioned in this blog and allows you to explore the different update flows and how they were set up. Unfortunately, due to the nature of In-App Updates, you won't be able to recreate this behavior until actually implementing them into your app or testing through a closed/internal test track on the Google Play Console. This sample application was tested and updated through an internal testing track.

What are In-App Updates?

In-app updates allow users to gain more control over when their applications get updated. For developers, once the download flow is handled, they just have to hand the restart and install off to Google Play and Play will provide UI for installation and restart.

Immediate: Immediate updates shows a full screen notifying the user that they need to update and restart to continue using the app. Once the user accepts, Google Play takes over and handles the installation and restart.

Flexible: Flexible updates allow the user to decide when they want the update to download and install. The UX provided prompts the user to download an update, lets them know when it is downloaded, and then notifies them that the application is ready to restart for installation. Throughout this whole flow, the user can continue to use their application without any interruptions.

Flexible Update

Implementation

Setup

Before beginning, make sure to include the dependency to use Play Core library 1.5.0 and have an app that only runs API 21 or higher. At the time of writing this blog, it appears that you also need to be using the Android App Bundle upload format. The sample application was uploaded using App Bundles.

To begin, check to see if an update is available using an instance of an AppUpdateManager and then add an OnSuccessListener to the manager.

AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);
appUpdateManager.getAppUpdateInfo().addOnSuccessListener(this);

For the purpose of the sample application, we implemented an OnSuccessListener<AppUpdateInfo> on our calling activity and implemented onSuccess.

@Override
 public void onSuccess(AppUpdateInfo appUpdateInfo) {
 if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
 if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
 //handle immediate flow
 } else if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
 //handle flexible flow
 }
 }
 }

The appUpdateInfo object returned back allows us to check the availability for an update and then what type of update is being returned. It also contains an intent to actually start the update which you then pass into startUpdateFlowForResult().

appUpdateManager.startUpdateFlowForResult(
 appUpdateInfo,
 appUpdateType,
 this,
 REQUEST_CODE);

The AppUpdateType parameter can either be IMMEDIATE or FLEXIBLE and both will kick off their respective update flows using the intent stored in appUpdateInfo. The third parameter is the calling activity and the final parameter is an int used as a request code to keep track of this update request. After starting an update, use an onActivityResult() callback to handle failure or cancellation.

Immediate Update

Once startUpdateFlowForResult is called with AppUpdateType.IMMEDIATE, Google Play takes over and shows a full-screen UI that handles the download and installation of the update.

If the app is closed/exited, the update downloads and installs in the background however when returning back to the app, you should make sure to check if an update is already running and resume the update.

Flexible Update

Once startUpdateFlowForResult is called with AppUpdateType.FLEXIBLE, the update begins downloading in the background. You can display the progress to the user by implementing an InstallStateUpdatedListener and use onStateUpdate to update the UI.

@Override
public void onStateUpdate(InstallState installState) {
 switch (installState.installStatus()) {
 case InstallStatus.DOWNLOADING:
 //show downloading UI
 break;
 case InstallStatus.DOWNLOADED:
 //handle downloaded update
 break;
 case InstallStatus.FAILED:
 //show failed UI/handle failed updated
 break;
 case InstallStatus.CANCELED:
 //show canceled UI/handle failed update
 break;
 }
}

Once you get the InstallStatus.DOWNLOADED update state, you need to prompt the user to restart for the app to install the update. Since this is a flexible update, once you let the user know that they need to restart, the user can continue to use the app freely or select to restart by calling appUpdateManager.completeUpdate() and Google Play will handle the rest of the flow to restart and install the update.

Similar to immediate updates, you should check for downloaded updated when bringing the app back to the foreground and install any updates or else it will just take up space on the user's phone.

Things to consider

  • PLAN PLAN PLAN! In-app updates require you to know in advance how you want to handle updates so planning exactly how you want things ahead of releasing is essential because once the update flows and UIs get released, you cannot change them until the next update.
  • Internal Test Tracks in the Google Play Console were an excellent tool to use when testing In-App Updates.
  • At the time of writing this blog, there is not an option to flag an update as immediate or flexible, but we anticipate that will come in the future either in code or in the Play Console due to the existing appUpdateInfo.isUpdateTypeAllowed() method
  • The request code (REQUEST_CODE used in startUpdateFlowForResult()) is an arbitrary positive integer and it needs to be the lower 16 bits, which means you need to keep it between 0 and 65535, otherwise, you'll get the following exception: java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
  • When testing, make sure the Google Play cache is up to date by closing the Play Store App and then going back to the My Apps & Games tab before testing updates.

Final Thoughts

In-App Updates are a great addition to any app that wants to add a more friendly update flow for their users. Users will be able to interact with their apps for however long they need to and install the update when they decide to instead of when the Play Store updates.

Authors

Alisher Pazylbekov is a Software Engineer and Senior Consultant at CapTech, based in Washington, DC. Alisher is passionate about bringing the latest and greatest technologies and patterns to his work. His area of expertise is Android Development.

Juan P. Garduno is a senior software engineer who is passionate and specialized in mobile development, in both Android and iOS platforms. Currently, he’s developing solutions in both platforms for a renowned hospitality company.