In-App Updates Flexible Flow: Speed Up the App Update Process on Android
With a variety of new tools and features announced at Android Dev Summit, special attention should be given to the In-App Updates (IAUs) API allowing developers to increase the speed of delivering features, bug-fixes and performance improvements to active users. Since this feature was finally released after Google I/O 2019, in this article I’ll deep dive on IAUs API, describe in details recommended user flows and provide with some code samples. Moreover, I'll share some experience of IAUs integration in the Pandao app, a marketplace platform for Chinese goods.
The new API allows developers to initiate a new in-app update request flow in order to push active users to update the app. IAUs complements the existing Google Play auto-update mechanism, but, unfortunately, does not have any impact on intentions of some users to disable any kind of updates. IAUs request can be implemented in two ways, which provide the completely different user experience.
- The flexible flow prompts users to download an update in the background and install it at a convenient moment. It is supposed to be used in cases while it is still appropriate for a user to use the older version of the app while the new one was released.
- The immediate flow requires users to download and install an update before continue using the app. It is supposed to be used in cases while it is crucial for developers to prevent usage of the app before the update is applied.
Since the latter use case is less important and appropriate for the Pandao app, we will discuss in detail the former.
IAUs Flexible Flow Integration
Use Case
The flexible IAUs flow consists of the following steps.
- The app requests Google Play to check for available updates using Play Core Library.
- If there is an available update, the app requests Google Play to show the IAUs dialogue. Google Play shows the update request dialogue to the user.
- If the user accepts update request, Google Play downloads an update in the background, providing the user with graceful state monitoring at the status bar.
- If the process of downloading completes while the app is in the background, Google Play automatically completes the installation. For cases when the download completes while the app is in the foreground, we have to define custom logic for the update completion. Consider several best-practices for the implementation.
- The app launches the installation process while displaying a Google Play screen with the installation progress to the user. After the installation is complete, the app restarts and an updated version opens. In this case, it is recommended to display an additional dialogue to allow the user to confirm explicitly that he or she is ready to relaunch app right now. This is a highly-recommended flow.
- The app waits until it goes to the background and then completes the update silently. One the one hand, this option is less invasive in terms of user experience. But on the other hand, it requires the developer to implement a tricky feature for detecting whenever the app goes to the background.
- The app launches the installation process while displaying a Google Play screen with the installation progress to the user. After the installation is complete, the app restarts and an updated version opens. In this case, it is recommended to display an additional dialogue to allow the user to confirm explicitly that he or she is ready to relaunch app right now. This is a highly-recommended flow.
In exceptional situations, the completion of the update will be deferred automatically to the Google Play background task. This option is not recommended for the explicit use because it doesn’t provide any guarantees about the installation of an update.
Basic Requirements for Manual Testing
In order to manually perform the full update flow on the test device, you should have at least two versions of the app with the different version number: a source version and a target version.
- The source version with the higher version number should be published at Google Play, this is the version which will be identified by Google Play as an available update. The target version with the lower version number and integrated IAUs feature should be installed on your device, this is the version which will be updated. The thing is, when the app requests Google Play to check for available updates, it compares the version number of the installed app with the version number of the last available build in Google Play. So the IAUs feature will be triggered only in case if the version number in Google Play is higher than actual version of the app on the device.
- Both the source and the target versions need to have the same package name and should be signed with the same release certificate.
- Android 5.0 (API level 21) or higher.
- Play Core library 1.5.0 or higher.
Sample Code
This section contains some sample code for IAUs usage, which is also can be found in the official documentation. To begin with, it’s necessary to add Play Core library to the module-level gradle file.
dependencies {
...
implementation "com.google.android.play:core:1.5.0"
}
Next, let’s create an instance of the IAUs manager and add callbacks to
AppUpdateInfo
task. The result of this task contains information about an update availability, an intent to start an update if it is available, and the current progress of the update download if it has already started.// Create instance of the IAUs manager.
val appUpdateManager = AppUpdateManagerFactory.create(context)
// Add state listener to app update info task.
appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
// If there is an update available, prepare to promote it.
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
// ...
}
// If the process of downloading is finished, start the completion flow.
if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
// ...
}
}
.addOnFailureListener { e ->
// Handle the error.
}
In terms of how to trigger the update request dialogue from Google Play in code, you receive a
PendingIntent
in the AppUpdateInfo
object, which you can start with startIntentSenderForResult
. This dialogue requests the user to start the update. appUpdateManager.startUpdateFlowForResult(
// Pass the intent that is returned by 'getAppUpdateInfo()'.
appUpdateInfo,
// Or 'AppUpdateType.IMMEDIATE for immediate updates.
AppUpdateType.FLEXIBLE,
// The current activity.
activity,
REQUEST_CODE
)
To monitor the update state, you can add
InstallStateUpdatedListener
to the IAUs manager. Please make sure your InstallStateUpdatedListener
is lifecycle-aware.// Create a listener to track downloading state updates.
val listener = InstallStateUpdatedListener { state ->
// Update progress indicator, request user to approve app reload, etc.
}
// At some point before starting an update, register a listener for updates.
appUpdateManager.registerListener(listener)
// ...
// At some point when status updates are no longer needed, unregister the listener.
appUpdateManager.unregisterListener(listener)
As soon as the update is downloaded (
DOWNLOADED
status), the app should be restarted in order to complete the update. It can be easily initiated by calling appUpdateManager.completeUpdate()
, but it’s recommended to display a snackbar to allow the user to confirm explicitly that he or she is ready to relaunch app right now. Snackbar.make(
rootView,
"An update has just been downloaded from Google Play",
Snackbar.LENGTH_INDEFINITE
).apply {
setAction("RELOAD") { appUpdateManager.completeUpdate() }
show()
}
«Update is Not Available» Error
First of all, please double check requirements mentioned in «Basic Implementation Requirements» section. If you successfully complete above listed steps in compliance with all requirements, though the update, according to the
onSuccess
callback, still is not available, please pay attention to the following trick. The most likely reason is that the Google Play app does not know about the update yet due to the internal caching mechanism. To make sure you have the cache fresh when testing manually you can refresh the cached version by going to the «My Apps & Games» screen in the Google Play app. As an alternative, you can simply clear the cache of the Google Play app in the settings. Note that this is just an issue for testing and does not affect end users since the cache is updated daily anyway.IAUs Flexible Flow in Pandao
As a part of early access program, we integrated IAUs flexible flow (recommended implemetation) in Pandao app, that is, a marketplace app offering products from Chinese manufacturers and vendors. The IAUs dialogue was shown at the main screen, so the maximum number of users were able to interact with it. Initially, we decided to show IAUs dialogue not more than once a day in order to avoid risk users being annoyed.
Since A/B testing is a pivotal step in every new feature lifecycle, we decided to evaluate the effect of IAUs on the Pandao app. We randomly divided our users into two non-overlapping groups. The first one is a control group without IAUs functional representing the ‘no-change’ baseline, and the second one is a test group with IAUs dialogue.
Fig. 1. A/B testing for IAUs (flexible flow) in Pandao App.
Over the past few releases, we measured the percentage of active users for each app version. It was found that among active users with the last available at a time version the major part was from group B, i.e. users with IAUS feature. As you can see from purple lines at fig. 1, in the first days after the publication of 1.29.1 app version, the number of active users with IAUs feature exceeded the number of users without this feature. The opposite situation can be observed for the previous versions of the app, see blue and red lines after the publication of 1.29.1 app version. Therefore, it can be stated that users with IAUs tend to update the app version more quickly.
Fig. 2. Confirmation rate at IAUs dialogue (flexible flow) in Pandao App.
According to Pandao analytics data (see fig. 2), conversion to click on the confirmation button at IAUs dialogue reaches peak values at the first days of the release and then constantly decreases until the next app update. The same pattern can be observed in conversion to click on the install button at a snackbar, which initiates installation of the downloaded update. Consequently, it seems like the average conversion rate in both cases directly proportional to the frequency of releases. In Pandao, the average conversion rate measured during one month exceeds 35% for click on the confirmation button and 7% for click on the install button.
We suggested that reducing of confirmation rate over time is just a user experience problem, because people that are interested in the new app version are going to update pretty quickly, and those that are not interested in updating will continue to not be interested. Based on this information we decided backing off some users if they are not interested in updating, rather than asking them every day. It seems to be a good practice trying different request logic based on 'staleness', i.e. how old the version they are on is, how many times a user has already asked them for an update and so on, rather than risk users being annoyed.
As a result, IAUs demonstrated valuable results during A/B test, so we rolled out this feature for all users.
Acknowledgments
I want to thank various colleagues for their contribution to this article. Thanks to Maryna Pliashkova Maryna_Pliashkova, Alexander Chernyy alexchernyy, Ilia Nazarov RolaRko, Gleb Bodyachevskiy, Daniil Polozov jokerdab, Anastasia Kulik, Vladislav Breus and Vladislav Goldin Vladiskus.