Blog Infos
Author
Published
Topics
,
Published
keep your app users up to date on their devices

Users may test out new features, have access to speed enhancements, and take advantage of bug fixes when they keep your software updated on their devices. Although some users choose to enable background updates when using an unmetered connection, other users might need a reminder to do so.

Active users are prompted to upgrade your app using the in-app updates functionality in Google Play Core libraries.

Devices running Android 5.0 (API level 21) or higher are compatible with the in-app updates feature.

Here are two methods for displaying updates within your app:

Flexible

If the user wants to update the app, a popup window will ask them. Both acceptance and denial are options. If they agree, the update will start downloading behind the scenes. When your update offers a few modest UI tweaks or performance upgrades, utilize this.

Photo on In-app updates

Immediate

The user must update the app in order to use this full-screen UX indefinitely. You can utilize this if you have a crucial update, such as a security patch.

Photo on In-app updates

There are two signals that can start the update:

  • Priority: You specify the update’s importance in each release by providing an integer that ranges from 0 to 5. (5 being the highest priority). In order to update the app, this will start the appropriate update flow (Immediate or Flexible).
  • Staleness: Specifies the amount of time the device has been aware that an update is available. This aids in setting off the appropriate flow. For instance, the Flexible flow would be triggered if the user hadn’t updated the app in the previous 30 days following the release of the update, and the Immediate flow would be triggered if it had been longer than 90 days.

For a better user experience, you may also combine the two signals.

How to implement in-app updates in Android

Add the following dependencies to your module-level gradle.build file.

dependencies {
implementation 'com.google.android.play:core:1.7.0'
}
view raw gradle.build hosted with ❤ by GitHub

We’re going to put everything we need in a separate file to make implementation simpler, and then we’re going to call it from the Activity we want to check for updates.

The following code should be pasted into a new file called InAppUpdate.kt

import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import com.google.android.play.core.appupdate.AppUpdateInfo
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.install.InstallState
import com.google.android.play.core.install.InstallStateUpdatedListener
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.InstallStatus
import com.google.android.play.core.install.model.UpdateAvailability
class InAppUpdate(activity: Activity) : InstallStateUpdatedListener {
private var appUpdateManager: AppUpdateManager
private val MY_REQUEST_CODE = 500
private var parentActivity: Activity = activity
private var currentType = AppUpdateType.FLEXIBLE
init {
appUpdateManager = AppUpdateManagerFactory.create(parentActivity)
appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
// Check if update is available
if (info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) { // UPDATE IS AVAILABLE
if (info.updatePriority() == 5) { // Priority: 5 (Immediate update flow)
if (info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
startUpdate(info, AppUpdateType.IMMEDIATE)
}
} else if (info.updatePriority() == 4) { // Priority: 4
val clientVersionStalenessDays = info.clientVersionStalenessDays()
if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 5 && info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Trigger IMMEDIATE flow
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 3 && info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Trigger FLEXIBLE flow
startUpdate(info, AppUpdateType.FLEXIBLE)
}
} else if (info.updatePriority() == 3) { // Priority: 3
val clientVersionStalenessDays = info.clientVersionStalenessDays()
if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 30 && info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Trigger IMMEDIATE flow
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 15 && info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Trigger FLEXIBLE flow
startUpdate(info, AppUpdateType.FLEXIBLE)
}
} else if (info.updatePriority() == 2) { // Priority: 2
val clientVersionStalenessDays = info.clientVersionStalenessDays()
if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 90 && info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Trigger IMMEDIATE flow
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 30 && info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Trigger FLEXIBLE flow
startUpdate(info, AppUpdateType.FLEXIBLE)
}
} else if (info.updatePriority() == 1) { // Priority: 1
// Trigger FLEXIBLE flow
startUpdate(info, AppUpdateType.FLEXIBLE)
} else { // Priority: 0
// Do not show in-app update
}
} else {
// UPDATE IS NOT AVAILABLE
}
}
appUpdateManager.registerListener(this)
}
private fun startUpdate(info: AppUpdateInfo, type: Int) {
appUpdateManager.startUpdateFlowForResult(info, type, parentActivity, MY_REQUEST_CODE)
currentType = type
}
fun onResume() {
appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
if (currentType == AppUpdateType.FLEXIBLE) {
// If the update is downloaded but not installed, notify the user to complete the update.
if (info.installStatus() == InstallStatus.DOWNLOADED)
flexibleUpdateDownloadCompleted()
} else if (currentType == AppUpdateType.IMMEDIATE) {
// for AppUpdateType.IMMEDIATE only, already executing updater
if (info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
startUpdate(info, AppUpdateType.IMMEDIATE)
}
}
}
}
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == MY_REQUEST_CODE) {
if (resultCode != AppCompatActivity.RESULT_OK) {
// If the update is cancelled or fails, you can request to start the update again.
Log.e("ERROR", "Update flow failed! Result code: $resultCode")
}
}
}
private fun flexibleUpdateDownloadCompleted() {
Snackbar.make(
parentActivity.findViewById(R.id.activity_main_layout),
"An update has just been downloaded.",
Snackbar.LENGTH_INDEFINITE
).apply {
setAction("RESTART") { appUpdateManager.completeUpdate() }
setActionTextColor(Color.WHITE)
show()
}
}
fun onDestroy() {
appUpdateManager.unregisterListener(this)
}
override fun onStateUpdate(state: InstallState) {
if (state.installStatus() == InstallStatus.DOWNLOADED) {
flexibleUpdateDownloadCompleted()
}
}
}
view raw InAppUpdate.kt hosted with ❤ by GitHub

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Put Your Tests on a Diet:Testing the Behavior and Not the Implementation

How do you write tests? How much time do you spend writing tests? And how much time do you spend fixing them when refactoring?
Watch Video

Put Your Tests on a Diet:Testing the Behavior and Not the Implementation

Stelios Frantzeskakis
Staff Engineer
PSS

Put Your Tests on a Diet:Testing the Behavior and Not the Implementation

Stelios Frantzeska ...
Staff Engineer
PSS

Put Your Tests on a Diet:Testing the Behavior and Not the Implementation

Stelios Frantzes ...
Staff Engineer
PSS

Jobs

Initialize the InAppUpdate.kt class and add the methods onResume and onActivityResults to your activity (often the MainActivity):

class MainActivity : AppCompatActivity() {
private lateinit var inAppUpdate: InAppUpdate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
inAppUpdate = InAppUpdate(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
inAppUpdate.onActivityResult(requestCode,resultCode, data)
}
override fun onResume() {
super.onResume()
inAppUpdate.onResume()
}
override fun onDestroy() {
super.onDestroy()
inAppUpdate.onDestroy()
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

When you use this code and set priority to:

5: Instantly displays Immediate (Recommended for critical updates)
4: Displays Immediacy after 5 days and Flexibility after 3 days.
3: Displays Immediate after 30 days and Flexible after 15 days (Recommended for performance updates)
2: Displays Immediacy after 90 days and Flexibility after 30 days (Recommended for minor updates)
1: Always Shows Flexibility
0: It has no effect on the update flow.

Of course, you are free to modify the code to suit your requirements.

There is no way to set the update’s priority through the Google Play Console; instead, you must use the Google Play Developer API.

Testing

You must upload your app twice to the internal (or alpha or beta) track in order to test your in-app update solution.

Thank you for taking the time to read this article. If you found this post to be useful and interesting, please clap and recommend it.

If I got something wrong, mention it in the comments. I would love to improve.

This article was originally published on proandroiddev.com on July 08, 2022

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Every good Android application should be well tested to minimize the risk of error…
READ MORE
blog
In this article we’ll go through how to own a legacy code that is…
READ MORE
blog

Running Instrumented Tests in a Gradle task

During the latest Google I/O, a lot of great new technologies were shown. The…
READ MORE

1 Comment. Leave new

  • Sumedh
    19.04.2023 13:34

    Can you specify steps and permissions needed to update the priority 0-5 for a release.

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu