javaandroidlocalbroadcastmanager

Fatal Exception: java.lang.SecurityException One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED (com.google.android.play:core


I am getting a crash with my android apps. Which shows security exception with the targetSDKVersion 34.

How to resolve this. The error is showing as below (playcore library) com.google.android.play.core.listener.zzc.zzb (com.google.android.play:core@@1.10.3:3)

Note: I am using the LocalBroadcastManager in my app. Is this issue raised because of this?

Code:

 LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, filter)

Error:

Fatal Exception: java.lang.SecurityException
pck: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
android.os.Parcel.createExceptionOrNull (Parcel.java:3057)

android.content.ContextWrapper.registerReceiver (ContextWrapper.java:755)
com.google.android.play.core.listener.zzc.zzb (com.google.android.play:core@@1.10.3:3)
com.google.android.play.core.listener.zzc.zzf (com.google.android.play:core@@1.10.3:4)
com.google.android.play.core.appupdate.zzf.registerListener (com.google.android.play:core@@1.10.3:1)
fragments.Summaryfragment.onCreate (Summaryfragment.java:144)
androidx.fragment.app.Fragment.performCreate (Fragment.java:2949)

androidx.appcompat.app.AppCompatActivity.onStart (AppCompatActivity.java:246)
ActionBarFragmentActivity.onStart (ActionBarFragmentActivity.java:358)
android.app.Instrumentation.callActivityOnStart (Instrumentation.java:1582)

com.android.internal.os.ZygoteInit.main (ZygoteInit.java:971)

Solution

  • Since Android 14 there is a requirement to specify the export flag when registering context-registered receivers - https://developer.android.com/about/versions/14/behavior-changes-14#runtime-receivers-exported

    Apps and services that target Android 14 and use context-registered receivers are required to specify a flag to indicate whether or not the receiver should be exported to all other apps on the device either RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED, respectively.

    If your MessageReceiver is supposed to be called only by the components within your app, then you should use RECEIVER_NOT_EXPORTED. If it is supposed to be accessible to components beyond your own app - use RECEIVER_EXPORTED.

    Now, before you try to apply the change, you have to migrate from the deprecated LocalBroadcastManager since it does not allow you to specify the export flag. I would advise you to use ContextCompat class to register the receiver now. Your code should look more or less like this now:

    import androidx.core.content.ContextCompat
    
    ContextCompat.registerReceiver(
        this,
        mMessageReceiver,
        filter,
        ContextCompat.RECEIVER_NOT_EXPORTED
    )
    

    Now this code will not throw an error now, but it still might not work - Android 14 introduced another restriction when it comes to sending implicit intents to non-exported components: https://developer.android.com/about/versions/14/behavior-changes-14#safer-intents

    In your case, if you're using the RECEIVER_EXPORTED flag, you should not worry about this change in this context.

    If you're using RECEIVER_NOT_EXPORTED (like on the code above) and you're calling the MessageReceiver with an implicit intent, probably using intent action:

    context.sendBroadcast(Intent(YOUR_APP_ACTION))
    

    then you should make that Intent explicit, because otherwise it would not be received on Android 14+:

    context.sendBroadcast(
        Intent(YOUR_APP_ACTION).apply {
            setPackage(context.packageName)
        }
    )
    

    Specifying a package makes the Intent explicit - the non-exported MessageReceiver is able to receive those intents now.