Android 12: Explicit android:exported Requirement
Overview
Starting with Android 12 (API level 31), Google introduced a critical security requirement: any app component (Activity, Service, BroadcastReceiver, or ContentProvider) that includes an intent filter must explicitly declare the android:exported
attribute. This change enhances app security by preventing unintended component exposure to other applications.
Problem Statement
When targeting Android 12 or higher, you may encounter build errors like:
"Manifest merger failed with multiple errors, see logs"
The specific error indicates:
android:exported needs to be explicitly specified for <activity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined.
This occurs when your app or its dependencies contain components with intent filters but without explicit android:exported
declarations.
Solutions
1. Add Explicit exported Attributes
For each component with intent filters, add android:exported="true"
or android:exported="false"
:
<!-- For activities -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- For services -->
<service
android:name=".MyService"
android:exported="false" />
<!-- For broadcast receivers -->
<receiver
android:name=".MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
2. Identify Missing exported Attributes
When the error originates from dependencies, use these approaches to locate problematic components:
Approach 1: Use Merged Manifest View
- Open your
AndroidManifest.xml
- Click the "Merged Manifest" tab at the bottom
- Look for components with intent filters but without
android:exported
attributes - Note the component names and their source libraries
Approach 2: Analyze Build Logs
Run this command to capture detailed build logs:
./gradlew assembleDebug --stacktrace --info | tee build-logs.txt
Search for these keywords in the generated file:
activity#
service#
receiver#
provider#
3. Override Library Components
For components from third-party libraries, override them in your main manifest:
<!-- Example for a problematic activity from a library -->
<activity
android:name="com.example.library.ProblematicActivity"
android:exported="false"
tools:node="merge"
tools:overrideLibrary="com.example.library" />
4. Update Dependencies
Outdated dependencies often cause this issue. Update these commonly problematic dependencies:
dependencies {
// Testing dependencies
androidTestImplementation 'androidx.test:core:1.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// Other commonly problematic libraries
implementation 'com.razorpay:checkout:1.6.15'
implementation 'com.google.dagger:hilt-android:2.40.5'
}
WARNING
Some libraries like flutter_local_notifications
have known issues with Android 12. Consider alternatives like awesome_notifications
if problems persist.
5. Temporary Workaround
If urgent, temporarily downgrade your target SDK (not recommended for production):
android {
defaultConfig {
targetSdkVersion 30
}
}
Common Scenarios and Fixes
Activities with Intent Filters
<activity
android:name=".SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Services and Receivers
<service
android:name=".MyService"
android:exported="false" />
<receiver
android:name=".MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Third-party Library Components
For RazorPay issues:
<receiver
android:name="com.razorpay.RzpTokenReceiver"
android:exported="false">
<intent-filter>
<action android:name="rzp.device_token.share" />
</intent-filter>
</receiver>
<activity
android:name="com.razorpay.CheckoutActivity"
android:exported="true"
android:theme="@style/CheckoutTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<data
android:host="rzp.io"
android:scheme="io.rzp" />
</intent-filter>
</activity>
Best Practices
- Always specify
android:exported
for components with intent filters - Use
exported="false"
for components only used within your app - Use
exported="true"
only for components that need to be accessible from other apps - Regularly update dependencies to ensure Android 12 compatibility
- Test thoroughly after making changes to manifest files
Troubleshooting
If issues persist after applying these fixes:
- Clean and rebuild your project
- Invalidate caches and restart Android Studio
- Check for multiple manifest files in your project
- Verify all library versions are compatible with Android 12
TIP
The exported
attribute controls whether components can be launched by other applications. Set it to true
only when necessary for interoperability.
Conclusion
The Android 12 android:exported
requirement enhances app security but requires careful attention to manifest declarations. By following these guidelines and keeping dependencies updated, you can ensure compliance while maintaining app functionality.
For more information, refer to the official Android documentation.