onActivityResult() deprecated for AppCompatActivity - android

I am using in-app updates for android and as per the documentation, they are using onActivityResult to handle app behaviour incase the update is interrupted.
This is my function that is called from my fragment:
private fun startImmediateUpdate(appUpdateInfo: AppUpdateInfo) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
requireActivity(),
Constants.CODES.APP_UPDATE_REQUEST_CODE
)
}
This is how i am handling results in parent activity
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
Constants.CODES.APP_UPDATE_REQUEST_CODE -> {
if (resultCode != RESULT_OK || resultCode == RESULT_CANCELED || resultCode == ActivityResult.RESULT_IN_APP_UPDATE_FAILED) {
//Do whatever i want to
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
Now super.onActivityResult(requestCode, resultCode, data) is deprecated. Things are working fine for now but i am worried the app will crash if its wiped out completely
What can i do to replace onActivityResult()? I have looked into registerForActivityResult() but could not find anything that suits my usecase.

As Ian Lake mentioned there is a solution that uses IntentSenderForResultStarter.
First of all in your Activity, create a ActivityResultLauncher:
private val updateFlowResultLauncher =
registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult(),
) { result ->
if (result.resultCode == RESULT_OK) {
// Handle successful app update
}
}
Now start the update flow as follows:
fun startUpdate(
appUpdateInfo: AppUpdateInfo,
requestCode: Int,
) {
val starter =
IntentSenderForResultStarter { intent, _, fillInIntent, flagsMask, flagsValues, _, _ ->
val request = IntentSenderRequest.Builder(intent)
.setFillInIntent(fillInIntent)
.setFlags(flagsValues, flagsMask)
.build()
updateFlowResultLauncher.launch(request)
}
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.FLEXIBLE,
starter,
requestCode,
)
}

I have the same issue and I see that one possibility is to rewrite to use the startUpdateFlow call instead.
Personally, I think this is not worth doing, so I will ignore this specific deprecation warning instead and wait/hope for Android/Google to make a method where we can pass an ActivityResultLauncher instead.

The New Way
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& (appUpdateInfo.clientVersionStalenessDays() ?: -1) >= 2
&& appUpdateInfo.updatePriority() >= updatePriority
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
updateCode
)
openActivityForResult()
}
}
}
private fun openActivityForResult(){
resultUpdate.launch(Intent(this, MainActivity::class.java))
}
var resultUpdate = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result->
if (result.resultCode != Activity.RESULT_OK){
Toast.makeText(
this,
"App Update failed, please try again on the next app launch.",
Toast.LENGTH_SHORT
).show()
}
}

Related

onActivityResult deprecated, is there alternative (KOTLIN)

Currently I am working on a project for my college, and i have discovered that onActivityResult is deprecated. What can be done to handle it?
This is my code that troubles me
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
val result = CropImage.getActivityResult(data)
if (resultCode == RESULT_OK) {
image = result.uri
Glide.with(this).load(image).into(binding.imgPick)
} else {
Snackbar.make(
binding.root,
"Image not selected",
Snackbar.LENGTH_SHORT
).show()
}
}
}
I tried to find a solution on stackoverflow and already tried to implement couple of thing but with no luck.
You can use the following way :
fun openActivityForResult() {
startForResult.launch(Intent(this, AnotherActivity::class.java))
}
val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// Handle the Intent
//do stuff here
}
}
You can use this in activity or fragment.
First define intent result launcher.
var picker: ActivityResultLauncher<Intent>
then
picker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK && it.data != null) {
//add your code here
}
}
And now launch your activity.
val intent = Intent(context, ImagePickerActivity::class.java)
picker.launch(intent)

In-App Update Finish Downloading But The Apps Still The Old Version

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.

Alternative to onActivityResult for startUpdateFlowForResult

What is the alternative to get callback for startUpdateFlowForResult in InAppUpdates instead of onActivityResult since it is deprecated?
We have to wait for Google Play team to migrate away from the deprecated APIs. You can follow this issue on Google's Issue Tracker.
Create this result launcher
private val updateFlowResultLauncher =
registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult(),
) { result ->
if (result.resultCode == RESULT_OK) {
// Handle successful app update
}
}
After that try to launch your intent like this
val starter =
IntentSenderForResultStarter { intent, _, fillInIntent, flagsMask, flagsValues, _, _ ->
val request = IntentSenderRequest.Builder(intent)
.setFillInIntent(fillInIntent)
.setFlags(flagsValues, flagsMask)
.build()
updateFlowResultLauncher.launch(request)
}
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.FLEXIBLE,
starter,
requestCode,
)
Give it a try!
You can use below code snippet alternative of onActivityResult()
First Activity
Step 1
private val openActivity =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
handleActivityResult(REQUEST_CODE, it)
}
Step 2
openActivity.launch(
Intent(this, YourClass::class.java).apply {
putExtra(ANY_KEY, data) // If any data you want to pass
}
)
Step 3
private fun handleActivityResult(requestCode: Int, result: ActivityResult?) {
Timber.e("========***handleActivityResult==requestActivty==$requestCode====resultCode=========${result?.resultCode}")
if (requestCode == REQUEST_CODE) {
when (result?.resultCode) {
Activity.RESULT_OK -> {
val intent = result.data // received any data from another avtivity
}
Activity.RESULT_CANCELED->{
}
}
}
}
In second class
val intent = Intent()
intent.putExtra(ANY_KEY, data)
setResult(Activity.RESULT_OK, intent)
finish()

Android app Play Core library in App update not working properly

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();
}
}

How to handle in app update Immediate mode when user clicks on close button?

As per documentation , for in app update API implementation I am using immediate mode. But there is close button on full screen UI. When user clicks on the close button, UI is dismissed. How to handle this immediate flow in this case as I don't want user to use my app?
Please try this.
override fun onResume() {
super.onResume()
if (listener != null) {
appUpdateManager.registerListener(listener)
}
appUpdateManager
.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
100
)
} else if (appUpdateInfo.updateAvailability()
== UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
IMMEDIATE,
this,
100
);
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100) {
when (resultCode) {
Activity.RESULT_OK -> {
Toast.makeText(this, "RESULT_OK", Toast.LENGTH_LONG).show()
}
Activity.RESULT_CANCELED -> {
Toast.makeText(this, "RESULT_CANCELED", Toast.LENGTH_LONG).show()
finish()
}
ActivityResult.RESULT_IN_APP_UPDATE_FAILED -> {
Toast.makeText(this, "RESULT_IN_APP_UPDATE_FAILED", Toast.LENGTH_LONG).show()
finish()
}
else -> {
Toast.makeText(this, "No result", Toast.LENGTH_LONG).show()
}
}
}
}
In case if user clicks on close button, you can get that callback in this condition resultCode == Activity.RESULT_CANCELED:-
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
// React to activity result and if request code == ResultActivity.REQUEST_CODE
if (requestCode == UPDATE_REQUEST_CODE) {
//when user clicks update button
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(mContext, "App download starts...", Toast.LENGTH_LONG).show()
} else if (resultCode == Activity.RESULT_CANCELED) {
//if user click on close button
Toast.makeText(mContext, "App download canceled.", Toast.LENGTH_LONG).show()
//Here you can do whatever you want (call finish() to close the app.)
} else if (resultCode == ActivityResult.RESULT_IN_APP_UPDATE_FAILED) {
Toast.makeText(mContext, "App download failed.", Toast.LENGTH_LONG).show()
}
return true
}
return false
}
I assume you want to disallow the users to use your app until they update the app?
To do that, you can listen to update status and if the user cancels, you can request to start the update again (maybe show a dialog/message to the user explaining why the update is necessary).
From the docs
Get a callback for update status
After starting an update, you can use an onActivityResult() callback to handle an update failure or cancellation, as shown below.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_REQUEST_CODE) {
if (resultCode != RESULT_OK) {
log("Update flow failed! Result code: " + resultCode);
// If the update is cancelled or fails,
// you can request to start the update again.
}
}
}

Categories

Resources