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

by
Maya Patel
android localbroadcastmanager

The Problem:

In an Android application, upon updating the targetSDKVersion to 34, a crash is encountered with the play core library. The error message indicates a security exception with the registration of a receiver using LocalBroadcastManager. The specific error is ‘One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn’t being registered exclusively for system broadcasts’. Determine the cause of the issue and suggest a solution to resolve the SecurityException.

The Solutions:

Solution 1: Specify the export flag when registering context-registered receivers

In Android 14, you need to specify the export flag when registering context-registered receivers. This is necessary to indicate whether the receiver should be exported to all other apps on the device or not. You can use either `RECEIVER_EXPORTED` or `RECEIVER_NOT_EXPORTED` as the export flag.

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`.

To register the receiver with the export flag, use the `ContextCompat` class instead of `LocalBroadcastManager`. The code should look like this:

ContextCompat.registerReceiver(
    this,
    mMessageReceiver,
    filter,
    ContextCompat.RECEIVER_NOT_EXPORTED
)

This will prevent the error about `One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts.`

However, note that if you are using `RECEIVER_NOT_EXPORTED` and you are calling the `MessageReceiver` with an implicit intent, you need to make the `Intent` explicit. This means setting the package name of the app in the `Intent`. Otherwise, the intent will not be received on Android 14+.

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

Solution 2: Specifying receiver flag

To resolve the issue, you need to specify a flag when registering the receiver to indicate whether it should be exported to all other apps on the device.

This can be done by following these steps:

1. Create an instance of BroadcastReceiver:

val br: BroadcastReceiver = MyBroadcastReceiver()

2. Create an instance of IntentFilter:

val filter = IntentFilter(YOUR_BROADCAST_FILTER)

3. Choose whether the broadcast receiver should be exported and visible to other apps on the device:

val listenToBroadcastsFromOtherApps = false
val receiverFlags = if (listenToBroadcastsFromOtherApps) {
    ContextCompat.RECEIVER_EXPORTED
} else {
    ContextCompat.RECEIVER_NOT_EXPORTED
}

4. Register the receiver by calling registerReceiver():

ContextCompat.registerReceiver(context, br, filter, receiverFlags)

Caution: If the broadcast receiver is exported, other apps could send unprotected broadcasts to your app.

Q&A

I updated my targetSDKVersion to 34, and after that, I started getting crashes with the LocalBroadcastManager with the following error message: java.lang.SecurityException: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED (com.google.android.play:core@@1.10.3:3)

Starting from Android 14, context-registered receivers must specify the exported flag using RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED. This requirement applies to the AndroidX Play Core library as well.

What is the purpose of the RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED flags?

The RECEIVER_EXPORTED flag indicates that the receiver should be exported and visible to other apps on the device, while the RECEIVER_NOT_EXPORTED flag indicates that the receiver is listening only for broadcasts sent by your app.