Android 14 Broadcast Receiver Exported Flag Requirement
Problem
Android 14 enforces stricter security requirements for broadcast receivers. Apps now receive a SecurityException
with the message: "One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts" if they register receivers without explicit export flags.
This error commonly occurs:
- When using SDKs/libraries with outdated broadcast registration patterns (like Tuya's
com.thingclips.smart
) - During runtime on Android 14 devices (API 34+)
- When registering receivers for non-system broadcasts without export flags
Recommended Solutions
1. Conditional Receiver Registration
Override registerReceiver()
in your Activity or Application class with version-specific logic:
Kotlin Implementation
// In MainActivity.kt or MainApplication.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
override fun registerReceiver(receiver: BroadcastReceiver?, filter: IntentFilter?): Intent? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED)
} else {
super.registerReceiver(receiver, filter)
}
}
Java Implementation
// In MainActivity.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import androidx.annotation.Nullable;
@Override
public Intent registerReceiver(
@Nullable BroadcastReceiver receiver,
IntentFilter filter
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
} else {
return super.registerReceiver(receiver, filter);
}
}
Testing Recommendation
Test on multiple device models. Some manufacturers require this override in MainActivity
, others in MainApplication
.
2. Update Affected Libraries
For com.thingclips.smart
(Tuya SDK) users, upgrade to v6.1.0+:
// build.gradle
implementation 'com.thingclips.smart:thingclips-smart:6.1.0'
After updating:
- Sync Gradle files
- Perform clean build:
./gradlew clean build
- Verify receivers in
AndroidManifest.xml
have explicitandroid:exported
flags:
<receiver
android:name=".YourReceiver"
android:exported="true" /> <!-- or false if internal only -->
3. Use AndroidX ContextCompat
For manual receiver registration with backward compatibility:
ContextCompat.registerReceiver(
context,
receiver,
intentFilter,
ContextCompat.RECEIVER_EXPORTED // Use NOT_EXPORTED for app-only broadcasts
)
4. Internal Receiver Handling
Local Broadcasts (App-Only)
For receivers solely communicating within your app:
// Deprecated but functional alternative
LocalBroadcastManager.getInstance(this)
.registerReceiver(receiver, intentFilter)
Security Note
RECEIVER_EXPORTED
: Allows broadcasts from other appsRECEIVER_NOT_EXPORTED
: Restricts broadcasts to your app only
Always choose the most restrictive option that meets your use case
Context & Best Practices
Platform Requirement: The export flag enforcement began in Android 13 (Tiramisu) and became mandatory in Android 14
Recipient Choices:
- Use
ContextCompat.RECEIVER_EXPORTED
for:- Receiving broadcasts from other apps
- System broadcasts without protected permissions
- Use
ContextCompat.RECEIVER_NOT_EXPORTED
for:- Internal app components communication
- Broadcasts with sensitive data
- Use
Testing: Always validate solutions on:
- Physical Android 14 devices
- Multiple OEM implementations (Samsung, Xiaomi, etc.)
- Emulators with the latest system images
::: note Performance Prefer LocalBroadcastManager or alternative IPC methods like LiveData
for app-internal communication to reduce system overhead. :::
Additional Considerations
- For React Native/Ionic/Capacitor: Apply the Activity/Application method overrides shown above
- For missing context issues: Always check nullability with
requireContext()
- Update all broadcast-dependent libraries (e.g., BillingClient v6.1.0+)
// Example: Update Play billing library
implementation 'com.android.billingclient:billing:6.2.0'