I'm implementing AppUpdateType.IMMEDIATE in-app-updates from Play Market using this guide: https://developer.android.com/guide/app-bundle/in-app-updates
When I test I can't finish update process - it just throws me back to old app where I get prompted to update again and again.
What am I doing wrong?
SplashActivity.kt
private fun checkAppUpdate() {
val appUpdateManager = getUpdateManager()
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
showError("Update available. You should update")
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
UPDATE_REQUEST_CODE
)
} else {
viewModel.loadData()
}
}
}
Maybe I should listen to apk download and start installing manually?
Related
Any option to customize the Google play update the default prompt from the google-play-core library.
I need a customized popup.
I have followed this doc to achieve in-app update modal.
https://developer.android.com/guide/playcore/in-app-updates
You should use a custom Dialog or fragment for it. and after clicking the update button you navigate direct to the playstore. like that
val appUpdateManager = AppUpdateManagerFactory.create(this)
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
Log.d(TAG, "checkForAppUpdate: checking update")
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(
AppUpdateType.FLEXIBLE
)
) {
updateDialog = Dialog(this, R.style.in_app_update_theme)
updateDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
updateDialog.setCancelable(false)
updateDialog.setContentView(R.layout.in_app_update)
val updateBtn = updateDialog.findViewById(R.id.updateBtn) as Button
val laterBtn = updateDialog.findViewById(R.id.laterBtn) as Button
updateBtn.setOnClickListener {
try {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=your package name")
)
)
} catch (ex: Exception) {
}
updateDialog.dismiss()
}
laterBtn.setOnClickListener { updateDialog.dismiss() }
updateDialog.show()
}
}
so I'm working on a In-Apps Update for my application that already published in Play Store. I follow the documentation and try to test it by lowering my version code then run it, but after finish downloading the app, it supposed to re-open the new version app from but it still re-open my current app which is the lower version. So it's like download for nothing.
I search and got some solution to try like :
installing using apk-release (didn't work)
trying another code for in-app update (still didn't work)
Here's my code :
I put it in my Login page
private val appUpdateManager: AppUpdateManager by lazy { AppUpdateManagerFactory.create(this) }
private val appUpdatedListener: InstallStateUpdatedListener by lazy {
object : InstallStateUpdatedListener {
override fun onStateUpdate(installState: InstallState) {
when {
installState.installStatus() == InstallStatus.DOWNLOADED -> popupSnackbarForCompleteUpdate()
installState.installStatus() == InstallStatus.INSTALLED -> appUpdateManager.unregisterListener(this)
else -> Log.i("TAG", "onStateUpdate: InstallStateUpdatedListener: state: %s"+installState.installStatus())
}
}
}
}
private fun checkForAppUpdate() {
// 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.
appUpdateManager.startUpdateFlowForResult(
// Pass the intent that is returned by 'getAppUpdateInfo()'.
appUpdateInfo,
// Or 'AppUpdateType.FLEXIBLE' for flexible updates.
AppUpdateType.IMMEDIATE,
// The current activity making the update request.
this,
// Include a request code to later monitor this update request.
APP_UPDATE_REQUEST_CODE)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == APP_UPDATE_REQUEST_CODE) {
if (resultCode != RESULT_OK) {
Toast.makeText(this,
"App Update failed, please try again on the next app launch.",
Toast.LENGTH_SHORT)
.show()
}
}
}
private fun popupSnackbarForCompleteUpdate() {
val snackbar = Snackbar.make(
findViewById(R.id.drawer_layout),
"An update has just been downloaded.",
Snackbar.LENGTH_INDEFINITE)
snackbar.setAction("RESTART") { appUpdateManager.completeUpdate() }
snackbar.setActionTextColor(ContextCompat.getColor(this, R.color.accent))
snackbar.show()
}
override fun onResume() {
super.onResume()
appUpdateManager
.appUpdateInfo
.addOnSuccessListener { appUpdateInfo ->
// If the update is downloaded but not installed,
// notify the user to complete the update.
if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
popupSnackbarForCompleteUpdate()
}
//Check if Immediate update is required
try {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
// If an in-app update is already running, resume the update.
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
APP_UPDATE_REQUEST_CODE)
}
} catch (e: IntentSender.SendIntentException) {
e.printStackTrace()
}
}
}
Please help me, I already tried to fixing it for 3 days but still have none of the solution are work for me.
I implemented in app update from google services
protected void checkUpdate() {
AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(this);
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
appUpdateInfoTask.addOnFailureListener(err -> onUpdateError());
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
try {
appUpdateManager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType.IMMEDIATE, this, UPDATE_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
onUpdateError();
}
} else {
onNoUpdate();
}
});
}
... implementation 'com.google.android.play:core:1.10.0'
It works just fine on most of the phones. But i had some where it does not trigger any callback (addOnFailureListener,addOnSuccessListener or addOnCompleteListener)
First 2 lines are executed then it jump over callbacks
One of the phone :
play store 27.1.14-21
android 9
Thx
I have implemented google play inApp update using play core Play Core library. When a new update is pushed app shows mandatory update notification using this library , downloads new update and shows update complete. But after i exit the app and relaunch it same circle continues. It shows update available please update again notification. I think after download the update is not actually taking place. Please help me with this issue.
fun initUpdate() {
val appUpdateManager = AppUpdateManagerFactory.create(this)
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
appUpdateManager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType. IMMEDIATE, this, MY_REQUEST_CODE
)}}}override fun initComponents() {
initUpdate()
//rest of the code//
}
I had the same issue, I got it working after signing the app(with the lower app version to be updated) with production-release KeyStore. I was using a debug keystore to sign it earlier.
Here is code to get the in-app update.
override fun onResume() {
super.onResume()
checkForVersionUpdate()
}
private fun checkForVersionUpdate() {
val appUpdateInfoTask = appUpdateManager.getAppUpdateInfo()
// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
startUpdateFlow(appUpdateInfo)
} else if ((appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE))) {
startUpdateFlow(appUpdateInfo)
}
}
}
private fun startUpdateFlow(appUpdateInfo: AppUpdateInfo) {
try {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
REQUEST_IMMEDIATE)
} catch (e: IntentSender.SendIntentException) {
e.printStackTrace()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_IMMEDIATE && resultCode == RESULT_CANCELED) {
checkForVersionUpdate();
}
}
I saw this dialog always appears when I open old version of Tokopedia app. Tokopedia suggests me to update the app.
The dialog gives me two methods to update the app:
Update now
Update when Wi-Fi available
If I select Lain Kali (Cancel), the dialog appears again on the next app open. But, if I select the second option, I open Play Store and see this behavior:
It really do update on background until my device is connected to Wi-Fi.
I want to mimic the same action like Tokopedia did, because some version of my app contains critical bug. I want to give users a better user experience.
Do you know how to show the dialog above?
This is possible using In-App Update provided by Google.
In-app updates works only with devices running Android 5.0 (API level 21) or higher, and requires you to use Play Core library 1.5.0 or higher. There are two types - 1.Flexible and 2. Immediate.
Follow this link and implement In-App Update as per your requirement.
https://developer.android.com/guide/app-bundle/in-app-updates
You can achieve this by using Support in-app updates
It only work from Android 5.0 (API level 21) or higher.
There are two types of Update Available with UX for in-app updates:
Flexible
Immediate
To Check for update availability
// Creates instance of the manager.
AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);
// Returns an intent object that you use to check for an update.
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
// For a flexible update, use AppUpdateType.FLEXIBLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Request the update.
}
});
Okay, here's the complete code as requested by #akshay_shahane.
Firstly, add this line on your app's build.gradle:
dependencies {
implementation 'com.google.android.play:core:1.6.1'
}
And inside your activity:
class MainActivity : AppCompatActivity(), InstallStateUpdatedListener {
private val appUpdateManager by lazy {
AppUpdateManagerFactory.create(this).also { it.registerListener(this) }
}
override fun onDestroy() {
if (Build.VERSION.SDK_INT >= 21) {
appUpdateManager.unregisterListener(this)
}
super.onDestroy()
}
override fun onResume() {
super.onResume()
if (Build.VERSION.SDK_INT >= 21) {
appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
// If the update is downloaded but not installed, notify the user to complete the update.
if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
popupSnackbarForCompleteUpdate()
} else if (it.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
&& it.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
appUpdateManager.startUpdateFlowForResult(it, AppUpdateType.IMMEDIATE, this, REQUEST_CODE_UPDATE_APP)
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == ActivityResult.RESULT_IN_APP_UPDATE_FAILED && requestCode == REQUEST_CODE_UPDATE_APP) {
Toast.makeText(this, "Update failed", Toast.LENGTH_SHORT).show()
}
}
override fun onStateUpdate(state: InstallState) {
when (state.installStatus()) {
InstallStatus.DOWNLOADED -> popupSnackbarForCompleteUpdate()
InstallStatus.REQUIRES_UI_INTENT -> {
Snackbar.make(findViewById(R.id.activity_main_layout),
"To perform the installation, a Play Store UI flow needs to be started.",
Snackbar.LENGTH_LONG
).show()
}
else -> {
val stateString = when (state.installStatus()) {
InstallStatus.FAILED -> "failed"
InstallStatus.PENDING -> "pending"
InstallStatus.DOWNLOADING -> "downloading"
InstallStatus.INSTALLING -> "installing"
InstallStatus.INSTALLED -> "installed"
InstallStatus.CANCELED -> "canceled"
else -> null
}
if (stateString != null) {
Snackbar.make(findViewById(R.id.activity_main_layout),
"An update is $stateString.",
Snackbar.LENGTH_SHORT
).show()
}
}
}
}
private fun popupSnackbarForCompleteUpdate() {
Snackbar.make(findViewById(R.id.activity_main_layout),
"An update is ready to install.",
Snackbar.LENGTH_INDEFINITE
).apply {
setAction("INSTALL") { appUpdateManager.completeUpdate() }
show()
}
}
#RequiresApi(21)
fun checkUpdateViaGooglePlay() {
appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
when (appUpdateInfo.updateAvailability()) {
UpdateAvailability.UPDATE_AVAILABLE -> {
if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo, AppUpdateType.FLEXIBLE, this, REQUEST_CODE_UPDATE_APP)
} else if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo, AppUpdateType.IMMEDIATE, this, REQUEST_CODE_UPDATE_APP)
}
}
UpdateAvailability.UPDATE_NOT_AVAILABLE -> {
Toast.makeText(this, R.string.no_updates_found, Toast.LENGTH_SHORT).show()
}
}
}.addOnFailureListener {
Toast.makeText(this, R.string.error_check_update, Toast.LENGTH_SHORT).show()
}
}
companion object {
const val REQUEST_CODE_UPDATE_APP = 8
}
}