How to implement In-App Updates in Android using Kotlin| In-app updates
When your users keep your app up to date on their devices, they can try new features and benefit from performance improvements and bug fixes.
In this article, we will learn how to implement In-App Updates in Android using Kotlin.
In-app updates is a Google Play Core libraries feature that prompts active users to update your app.
Update flows
Your app can use the Google Play Core libraries to support the following UX flows for in-app updates:
Notes:
- The in-app updates feature is supported on devices running Android 5.0 (API level 21) or higher.
- In-app updates are only supported for Android mobile devices, Android tablets, and Chrome OS devices.
- In-app updates are not compatible with apps that use APK expansion files (.obb files).
- A popup appears, asking the user if they want to update the app.
- They can accept or deny it. If they accept it, the update will download in the background.
- This can be used when your update has some minor UI changes or performance improvements.
- This is a full-screen UX that requires the user to update the app to continue using it.
- This can be used when you have a critical update, like a security fix.
// In your app’s build.gradle.kts file:
...
dependencies {
// This dependency is downloaded from the Google’s Maven repository.
// 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.0")
...
}
val appUpdateManager = AppUpdateManagerFactory.create(context)
// Returns an intent object that you use to check for an update.
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
// This example applies an immediate update. To apply a flexible update
// instead, pass in AppUpdateType.FLEXIBLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
// Request the update.
}
}
val appUpdateManager = AppUpdateManagerFactory.create(context)
// Returns an intent object that you use to check for an update.
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
// Checks whether the platform allows the specified type of update,
// and current version staleness.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& (appUpdateInfo.clientVersionStalenessDays() ?: -1) >= DAYS_FOR_FLEXIBLE_UPDATE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Request the update.
}
}
package com.boltuix.materialuiux
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import android.view.Menu
import android.view.MenuItem
import androidx.lifecycle.MutableLiveData
import com.boltuix.materialuiux.databinding.ActivityMainBinding
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 MainActivity : AppCompatActivity() {
//.......................................................................
private lateinit var appUpdateManager: AppUpdateManager
private val updateAvailable = MutableLiveData<Boolean>().apply { value = false }
private var updateInfo: AppUpdateInfo? = null
private var updateListener = InstallStateUpdatedListener { state: InstallState ->
commonLog("update01:$state")
if (state.installStatus() == InstallStatus.DOWNLOADED) {
showUpdateSnackbar()
}
}
private fun checkForUpdate() {
appUpdateManager.appUpdateInfo.addOnSuccessListener {
if (it.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
it.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
updateInfo = it
updateAvailable.value = true
commonLog("update01:Version code available ${it.availableVersionCode()}")
startForInAppUpdate(updateInfo)
} else {
updateAvailable.value = false
commonLog("update01:Update not available")
}
}
}
private fun startForInAppUpdate(it: AppUpdateInfo?) {
appUpdateManager.startUpdateFlowForResult(it!!, AppUpdateType.FLEXIBLE, this, 1101)
}
private fun showUpdateSnackbar() {
try{
val snackbar = Snackbar.make(binding.coordinator, "An update has just been downloaded.", Snackbar.LENGTH_INDEFINITE)
.setAction("RESTART") { appUpdateManager.completeUpdate() }
//snackbar.anchorView = binding.appBarMain.contentMain.bottomNav
snackbar.setActionTextColor(Color.parseColor("#ffff4444"))
snackbar.show()
}catch (e:java.lang.Exception){
}
}
private fun commonLog(message :String) {
Log.d("tag001",message)
}
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
val navController = findNavController(R.id.nav_host_fragment_content_main)
appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
binding.fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAnchorView(R.id.fab)
.setAction("Action", null).show()
}
try{
//.......................................................................
appUpdateManager = AppUpdateManagerFactory.create(this)
appUpdateManager.registerListener(updateListener)
checkForUpdate()
}catch (e:Exception){
commonLog("update01:Update e1 ${e.message}")
}
}
override fun onBackPressed() {
try{
appUpdateManager.unregisterListener(updateListener)
}catch (e:Exception){
commonLog("update01:Update e2 ${e.message}")
}
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_main)
return navController.navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
}
Comments
Post a Comment