Skip to content

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":

xml
<!-- 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

  1. Open your AndroidManifest.xml
  2. Click the "Merged Manifest" tab at the bottom
  3. Look for components with intent filters but without android:exported attributes
  4. Note the component names and their source libraries

Approach 2: Analyze Build Logs

Run this command to capture detailed build logs:

bash
./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:

xml
<!-- 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:

gradle
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):

gradle
android {
    defaultConfig {
        targetSdkVersion 30
    }
}

Common Scenarios and Fixes

Activities with Intent Filters

xml
<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

xml
<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:

xml
<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

  1. Always specify android:exported for components with intent filters
  2. Use exported="false" for components only used within your app
  3. Use exported="true" only for components that need to be accessible from other apps
  4. Regularly update dependencies to ensure Android 12 compatibility
  5. Test thoroughly after making changes to manifest files

Troubleshooting

If issues persist after applying these fixes:

  1. Clean and rebuild your project
  2. Invalidate caches and restart Android Studio
  3. Check for multiple manifest files in your project
  4. 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.