Keeping your app up-to-date on your users’ devices enables them to try new features, as well as benefit from performance improvements and bug fixes. Although some users enable background updates when their device is connected to an unmetered connection, other users may need to be reminded to update. In-app updates is a Play Core library feature that introduces a new request flow to prompt active users to update your app.
Google announced in-app update feature at Google I/0 2019. The related implementation guide contains enough clues on how to implement both FLEXIBLE and IMMEDIATE update ‘flavors’. However the suggested approach may not work perfect especially in multi-activity applications. In this article I’ll try to highlight some key points of implementing in-app update in a complex real-world app and introduce a small library born as a result of these efforts.
motorro/AppUpdateWrapperA wrapper for Android AppUpdateManager to simplify in-app update flow. A complete lifecycle-aware component to take a... |
The focus of the story will be on a FLEXIBLE flow as carrying out a background update task requires considerably greater effort than IMMEDIATE flow.
The article assumes you already have some experience in implementing in-app update for Android. Otherwise please check out the official implementation guide or some introductory story like this one:
Exploring in-app updates on AndroidI'm sure there has often been a time when you've needed to send out an app update that has some form of urgency - maybe... |
![]() |
Managing a flow state

The FLEXIBLE flow provides background update checking and downloading while user continues to interact with application UI. AppUpdateManagerchecks for update for you and updates you with state changes while update is being downloaded. Starting an update check in your activity onResumehandler seems to be a good point to start the flow so the UI interaction takes place only at the topmost activity. If update is available you start the update flow and AppUpdateManager pops up a new activity-for-result to confirm update:
Suppose, user confirms update, update manager starts download… So far so good just like in an official guide.
But what if user cancels? The onActivityResult handler will receive RESULT_CANCELED result code. Having update check in subsequent onResume handler will bring the consent screen back unless we implement some special processing and memoing of user interaction.
What we have here is AppUpdateManager is handling a ‘system’ update statebut the burden of the update UI flow lays on the developer. And things become trickier if you add multi-activity setup, screen rotation, a telephone call that interrupts application flow, you name it… Plus you need to get a correct state of update if your activity has started while say a download is underway.
Designed for single activity application
From what I’ve learned while trying to plug-in flexible flow in our main application it seems the AppUpdateManager is designed (and tested) for a single-activity design.
- Some effort in lifecycle management required to make multi-activity application to start download in one activity and to complete update in another.
- I haven’t managed to make several instances of AppUpdateManager work along each other in an application with several activities. Have to use a singleton instance which is an obvious solution but…
- AppUpdateManager fails to handle more than one active InstallStateUpdatedListener. If they try to unsubscribe within event dispatch manager crashes with ConcurrentModificationException. Take a look at this test:
Crashes when unsubscribing
AppUpdateWrapper to the rescue!
All in all, after some considerable time of trial and error spent I’ve come to the solution which IMO simplifies most of the update flow implementation in your application.
Here is how the minimum activity setup looks like with AppUpdateWrapperat your side:
Minimum activity setup for update flow
Features
- You only need to implement a single AppUpdateView interface with minimum of three required methods to run both IMMEDIATE and FLEXIBLE flows. You may implement it in your activity as shown above or delegate to any view component of your choice.
- The AppUpdateWrapper is a lifecycle-aware component designed as a plugin.
- Works nice across multiple activities including a workaround to crashes with event listeners.
- Under the hood based on a ‘state-machine’ pattern for clean and testable code to test each key point.
Bonus
As a bonus the FLEXIBLE flow of a library offers a built-in solution to postpone subsequent update prompts if user has already canceled the update:
The library implements couple of basic use-cases:
- alwaysOn — to ask user every time the update is found
- forOneDay — to postpone the next update prompt for one day since cancellation
From this article you’ve learnt about the possible difficulties to build a smooth update flow UI for Android application. Also the AppUpdateWrapperlibrary was presented to you as possible solution to problems above-mentioned. For the further details on using AppUpdateWrapper in your application please refer to the Github repository. If you have any questions about the library or in-app updates then please do reach out. It will also be great if you could try the solution in your application and to contribute to the code or test scenario.
motorro/AppUpdateWrapperA wrapper for Android AppUpdateManager to simplify in-app update flow. A complete lifecycle-aware component to take a... |
![]() |