I have an android app which uses in-app-updates. After targeting android 14 (API 34) the app will not start due to this error:
FATAL EXCEPTION: main
Process: no.norva24.mslam, PID: 8281
java.lang.RuntimeException: Unable to start activity
ComponentInfo{no.norva24.mslam/no.norva24.mslam.ui.activities.MainActivity}: java.lang.SecurityException: no.norva24.mslam: One
of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered
exclusively for system broadcasts
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8176)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: java.lang.SecurityException: no.norva24.mslam: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED
should be specified when a receiver isn't being registered exclusively for system broadcasts
at android.os.Parcel.createExceptionOrNull(Parcel.java:3057)
at android.os.Parcel.createException(Parcel.java:3041)
at android.os.Parcel.readException(Parcel.java:3024)
at android.os.Parcel.readException(Parcel.java:2966)
at android.app.IActivityManager$Stub$Proxy.registerReceiverWithFeature(IActivityManager.java:5668)
at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1852)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1792)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1780)
at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:755)
at com.google.android.play.core.listener.zzc.zzb(com.google.android.play:core@@1.10.3:3)
at com.google.android.play.core.listener.zzc.zzf(com.google.android.play:core@@1.10.3:4)
at com.google.android.play.core.appupdate.zzf.registerListener(com.google.android.play:core@@1.10.3:1)
at no.norva24.mslam.utilities.updates.InAppUpdate.<init>(InAppUpdate.kt:62)
at no.norva24.mslam.ui.activities.MainActivity.onCreate(MainActivity.kt:741)
at android.app.Activity.performCreate(Activity.java:8595)
at android.app.Activity.performCreate(Activity.java:8573)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8176)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: android.os.RemoteException: Remote stack trace:
at
com.android.server.am.ActivityManagerService.registerReceiverWithFeature(ActivityManagerService.java:13895)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2563)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2708)
at android.os.Binder.execTransactInternal(Binder.java:1339)
at android.os.Binder.execTransact(Binder.java:1275)
I have not seen any explanation on how to set those settings.
Following code is used for in-app-updates:
package no.norva24.mslam.utilities.updates
import android.app.Activity
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
import com.google.android.play.core.ktx.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import no.norva24.mslam.repositories.Message
import no.norva24.mslam.ui.activities.MainActivity
import no.norva24.mslam.utilities.definitions.SELF_UPDATE_REQUEST_CODE
import java.lang.Exception
class InAppUpdate(activity: Activity): InstallStateUpdatedListener {
var TAG = javaClass.simpleName
private var appUpdateManager: AppUpdateManager
private var parentActivity: Activity = activity
private var currentType = AppUpdateType.FLEXIBLE
init {
Log.i(TAG, "init: I100: Init InAppUpdate")
appUpdateManager = AppUpdateManagerFactory.create(parentActivity)
appUpdateManager.appUpdateInfo.addOnSuccessListener { info->
Log.i(TAG, "init: I100: update info $info")
if (info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE){
Message.info("App update available !")
if((info.clientVersionStalenessDays?:0)<5){
if(info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)){
startUpdate(info, AppUpdateType.FLEXIBLE)
} else {
Message.info("App update may be available on Google Play !")
}
} else {
if(info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)){
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if(info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)){
startUpdate(info, AppUpdateType.FLEXIBLE)
} else {
Message.info("App update may be available on Google Play !")
}
}
} else {
Log.i(TAG, "I100: init: no update available")
}
}
appUpdateManager.registerListener(this)
}
private fun startUpdate(info: AppUpdateInfo, type: Int){
try {
appUpdateManager.startUpdateFlowForResult(info,type,parentActivity, SELF_UPDATE_REQUEST_CODE)
currentType = type
}catch (exception:Exception){
Message.error(exception.message.toString())
}
}
fun onResume(){
appUpdateManager.appUpdateInfo.addOnSuccessListener { info->
if(currentType == AppUpdateType.FLEXIBLE){
if(info.installStatus() == InstallStatus.DOWNLOADED)
flexibleUpdateDownloadCompleted()
} else if (currentType == AppUpdateType.IMMEDIATE){
if(info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
startUpdate(info, AppUpdateType.IMMEDIATE)
}
}
}
}
fun onActivityResult(requestCode: Int, resultCode: Int){
if(requestCode == SELF_UPDATE_REQUEST_CODE){
if(resultCode != AppCompatActivity.RESULT_OK){
Message.error("Update flow failed: $resultCode")
}
}
}
fun checkForUpdates(){
CoroutineScope(Dispatchers.IO).launch {
Log.i(TAG, "checkForUpdates: requesting appUpdateInfo")
val appUpdateInfo = appUpdateManager.requestAppUpdateInfo()
Log.i(TAG, "checkForUpdates: appUpdateInfo returned")
Log.i(TAG, "checkForUpdates: available version code..........: ${appUpdateInfo.availableVersionCode()}" )
Log.i(TAG, "checkForUpdates: bytes downloaded................: ${appUpdateInfo.bytesDownloaded}" )
Log.i(TAG, "checkForUpdates: client version staleness days...: ${appUpdateInfo.clientVersionStalenessDays}" )
Log.i(TAG, "checkForUpdates: install status..................: ${appUpdateInfo.installStatus}" )
Log.i(TAG, "checkForUpdates: is update type allowed flexible.: ${appUpdateInfo.isFlexibleUpdateAllowed}" )
Log.i(TAG, "checkForUpdates: is update type allowed immediate: ${appUpdateInfo.isImmediateUpdateAllowed}" )
Log.i(TAG, "checkForUpdates: package name ...................: ${appUpdateInfo.packageName()}" )
Log.i(TAG, "checkForUpdates: total bytes to download.........: ${appUpdateInfo.totalBytesToDownload}" )
Log.i(TAG, "checkForUpdates: update availability ............: ${appUpdateInfo.updateAvailability()}" )
Log.i(TAG, "checkForUpdates: update priority ................: ${appUpdateInfo.updatePriority}" )
when(appUpdateInfo.updateAvailability()){
UpdateAvailability.UPDATE_AVAILABLE-> {
if(appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)){
startUpdate(appUpdateInfo, AppUpdateType.FLEXIBLE)
} else {
Message.warning("App version ${appUpdateInfo.availableVersionCode()} should be ready\nPlease check Google Play")
}
}
UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS -> {
Message.warning("App update is already in progress, ${appUpdateInfo.bytesDownloaded}/${appUpdateInfo.totalBytesToDownload} bytes downloaded")
}
UpdateAvailability.UNKNOWN -> {
Message.error("Unknown error occurred checking updates")
}
UpdateAvailability.UPDATE_NOT_AVAILABLE -> {
Message.info("No updates available at the moment")
}
}
}
}
private fun flexibleUpdateDownloadCompleted(){
Snackbar.make(
(parentActivity as MainActivity).binding.appBarMain.coordinatorLayout,
"An app update has just been downloaded. Please restart app.",
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()
}
}
}
Should there be some additonal parameters in the manifest.xml
which isn't properly documented yet ?
The current version of Play In-App Updates Library you're using (1.10.3) doesn't support Android 14. You must upgrade it to version 2.1.0 that supports the new Android OS.
More here: https://developer.android.com/reference/com/google/android/play/core/release-notes-in_app_updates