In-App Update in Android 2023
I will show you how to implement in-app update in this article.
Introduction
In this article, we will learn about the In-app update feature in Android what is all about In-app update, what are the benefits of using the In-app update in your android application. Why dowe need to Implement this?
As a Developer we always want our users to have the updated version of their application but there are a lot of people who actually turned off their auto update from google play store and he/she doesn’t know about any update available or not.
To overcome the problem Google Introduced this feature called In-app update from this feature you can easily prompt the user to update the application and with the user permission you can update the application also while updating the app user can be able to interact with the application. Now the user doesn’t need to go to google play store to check there is any update available or not.
When your users keep your app up to date on their devices, they can 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 might need to be reminded to install updates. In-app updates is a Google Play Core libraries feature that prompts active users to update your app.
The in-app updates feature is supported on devices running Android 5.0 (API level 21) or higher. Additionally, in-app updates are only supported for Android mobile devices, Android tablets, and ChromeOS devices.
Update flows
Your app can use the Google Play Core libraries to support the following UX flows for in-app updates:
There are two modes of an In-app update.
- Flexible Update
- Immediate Update
Flexible updates
Flexible updates provide background download and installation with graceful state monitoring. This UX flow is appropriate when it’s acceptable for the user to use the app while downloading the update. For example, you might want to encourage users to try a new feature that’s not critical to the core functionality of your app.
Immediate updates
Immediate updates are fullscreen UX flows that require the user to update and restart the app in order to continue using it. This UX flow is best for cases where an update is critical to the core functionality of your app. After a user accepts an immediate update, Google Play handles the update installation and app restart.
Implementation:
Let’s start with the In-App update implementation, what we need to do first.
Step 1: Add Dependency
Add the Google App UpdateDependency to your android build.gradle
file, like the below code snippet.
// So, make sure you also include that repository in your project's build.gradle file.
implementation("com.google.android.play:app-update:2.0.1")
// For Kotlin users also import the Kotlin extensions library for Play In-App Update:
implementation("com.google.android.play:app-update-ktx:2.0.1")
Step 2: Create an AppManager Instance
We need to create an instance of the AppManager
to get the in-app update info, you can define this in your OnCreate method
like below code snippet:
// Creates instance of the manager in your onCreate() of Activity or onCreateView() of Fragment Method
private val appUpdateManager: AppUpdateManager? = AppUpdateManagerFactory.create(this)
Step 3: Check for the Update
Before requesting an update, check if there is an update available for your app. Use AppUpdateManager
to check for an update:
private fun checkUpdate() {
val appUpdateInfoTask = appUpdateManager?.appUpdateInfo
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
// This example applies an flexible update. To apply a immediate update
// instead, pass in AppUpdateType.IMMEDIATE
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)
) {
// Request the update
} else {
Log.d(TAG, "No Update available")
}
}
}
In the above code, I created a function with the name checkUpdate()
in which I first get the app update information using the appUpdateManager
instance which I was created earlier, in step 2 & assigned to another variable called appUpdateInfoTask
now everything seems perfectly going good, and now we have the info available we just need to add a listener to check whether the new update is available or not.
In addOnSuccessListener
we need to first check If update available or not with the function updateAvailability()
this will return the Boolean value, and also set the mode Flexible | Immediate. If both the condition meets then we have the update available and we are good to go for the update request.
The returned AppUpdateInfo
instance contains the update availability status. Depending on the status of the update, the instance also contains the following:
- If an update is available and the update is allowed, the instance also contains an intent to start the update.
- If an in-app update is already in progress, the instance also reports the status of the in-progress update.
Step 4. Define Launcher to get a callback for update status
After starting an update, registered activity result launcher callback gets the confirmation dialog result:
private val updateLauncher = registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult()
) { result ->
// handle callback
if (result.data == null) return@registerForActivityResult
if (result.resultCode == UPDATE_REQUEST_CODE) {
Toast.makeText(context, "Downloading stated", Toast.LENGTH_SHORT).show()
if (result.resultCode != Activity.RESULT_OK) {
Toast.makeText(context, "Downloading failed" , Toast.LENGTH_SHORT).show()
}
}
There are several values you might receive from the onActivityResult()
callback:
RESULT_OK
: The user has accepted the update. For immediate updates, you might not receive this callback because the update should already be finished by the time control is given back to your app.RESULT_CANCELED
: The user has denied or canceled the update.ActivityResult.RESULT_IN_APP_UPDATE_FAILED
: Some other error prevented either the user from providing consent or the update from proceeding.
Step 5: Request for the Update
In Step 5, we will learn how to request for the update, To update the request we need to use AppUpdateManager.startUpdateFlowForResult()
like the below code snippet:
try {
appUpdateManager?.startUpdateFlowForResult(
// Pass the intent that is returned by 'getAppUpdateInfo()'.
appUpdateInfo,
// an activity result launcher registered via registerForActivityResult
updateResultStarter,
//pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
// flexible updates.
AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build(),
// Include a request code to later monitor this update request.
UPDATE_REQUEST_CODE
)
} catch (exception: IntentSender.SendIntentException) {
Toast.makeText(context, "Something wrong went wrong!", Toast.LENGTH_SHORT).show()
}
Define IntentSenderForResultStarter
private val updateResultStarter =
IntentSenderForResultStarter { intent, _, fillInIntent, flagsMask, flagsValues, _, _ ->
val request = IntentSenderRequest.Builder(intent)
.setFillInIntent(fillInIntent)
.setFlags(flagsValues, flagsMask)
.build()
// launch updateLauncher
updateLauncher.launch(request)
}
Step 6: Monitor the flexible update state
After the download begins for a flexible update, your app needs to monitor the update state to know when the update can be installed and to display the progress in your app’s UI.
You can monitor the state of an update in progress by registering a listener for install status updates. You can also provide a progress bar in the app’s UI to inform users of the download’s progress.
// Create a listener to track request state updates.
val listener = InstallStateUpdatedListener { state ->
// (Optional) Provide a download progress bar.
if (state.installStatus() == InstallStatus.DOWNLOADING) {
val bytesDownloaded = state.bytesDownloaded()
val totalBytesToDownload = state.totalBytesToDownload()
// Show update progress bar.
}
if (state.installStatus() == InstallStatus.DOWNLOADED) {
Snackbar.make(
view,
"New app is ready",
Snackbar.LENGTH_INDEFINITE
).setAction("Restart") {
appUpdateManager.completeUpdate()
}.show()
}
// Log state or install the update.
}
After monitoring the update status and you detect the InstallStatus.DOWNLOADED
state. Now you need to restart the app to install the update so for that we need to just call completeUpdate()
function like the below code snippet:
appUpdateManager.completeUpdate()
And after the complete update, the app will restart and now you are in the new version of the application.
Step 7: Register the Listener
First register the listener before starting the update, like the below code:
// Before starting an update, register a listener for updates.
appUpdateManager.registerListener(listener)
Step 8: Unregister the Listener
when there is no need longer for the listener then we need to unregister the listener, to avoid the memory leak. like the below code:
// When status updates are no longer needed, unregister the listener.
appUpdateManager.unregisterListener(listener)
Note: Monitoring the update state is required for only flexible downloads
Handle an immediate update
When you start an immediate update and the user consents to begin the update, Google Play displays the update progress on top of your app’s UI throughout the entire duration of the update. If the user closes or terminates your app during the update, the update should continue to download and install in the background without additional user confirmation.
However, when your app returns to the foreground, you should confirm that the update is not stalled in the UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
state. If the update is stalled in this state, resume the update:
// Checks that the update is not stalled during 'onResume()'.
// However, you should execute this check at all entry points into the app.
override fun onResume() {
super.onResume()
appUpdateManager
.appUpdateInfo
.addOnSuccessListener { appUpdateInfo ->
...
if (appUpdateInfo.updateAvailability()
== UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
) {
// If an in-app update is already running, resume the update.
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
activityResultLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build())
}
}
}
How to Test:
Now the last thing is how to test this, this is a tricky part, the following things for testing you need to be followed.
Test with internal app sharing
Use internal app sharing to test in-app updates by performing the following steps:
- Make sure your test device has a version of your app installed that supports in-app updates and was installed using an internal app sharing URL.
- Follow the Play Console instructions to share your app internally. Upload a version of your app that uses a version code that is higher than the one you already have installed on the test device.
- On the test device, click the internal app sharing link for the updated version of your app but do not install the app from the Play Store page that appears after you click the link.
- Open the app from the device’s app drawer or home screen. The update should now be available to your app, and you can test your implementation of in-app updates.
I divided it into two parts.
Part1
- Generate a signed APK for Production.
- Go to App-Internal-Sharing and upload the build over there, and share the link with the tester
- Now install that build with the shareable link.
Part2
- Generate a signed APK for Production with another version code and version name, make sure the version which you upload earlier is lower than this.
- Go to App-Internal-Sharing and upload the build over there and share the link with the tester.
- Now click to that link and don’t click to the Update button.
- Now just open the application which you installed earlier you will get the update dialog.
Note: Every time you upload the Build make sure you close the Google Play Store App
Troubleshoot
This section describes some possible solutions to situations where in-app updates might not work as expected during testing:
- In-app updates are only available to user accounts that own the app. Make sure the account that you’re using has downloaded your app from Google Play at least once before using the account to test in-app updates.
- Make sure that the app that you are using to test in-app updates has the same application ID and signing key as the version available from Google Play.
- Google Play can only update an app to a higher version code. Make sure that the app that you are testing has a lower version code than the update version code.
- The
inAppUpdatePriority
field is not supported when uploading your app to internal app sharing.
Conclusion
This article taught you how to Implement an in-App update in your android application with the two different modes, one is Flexible and one is Immediate, how you can request again, how to monitor the status of the update, and how to test with the Internal app-sharing.
If you want to read more about, check out the official developer documentation below:
In-app updates | Android Developers
Check this Demo Project with Flexible mode In-App update