Skip to content

Android 12 Manifest Merger Failed: Fixing the android:exported Error

Problem Overview

Starting with Android 12 (API level 31), Google introduced a critical security change requiring explicit declaration of the android:exported attribute for components that use intent filters. This change affects activities, services, and broadcast receivers in your Android application.

When targeting Android 12 or higher, you'll encounter the build error:

Manifest merger failed: 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 error prevents your app from building and installing on Android 12+ devices until you address all missing android:exported declarations.

Understanding the android:exported Attribute

The android:exported attribute determines whether a component (activity, service, or broadcast receiver) can be accessed by components outside your application:

  • true: Any app can access the component using its exact class name
  • false: Only components within the same application, applications with the same user ID, or privileged system components can access it

Historical Context

In earlier Android versions, the default value for android:exported varied by component type and API level. For example, activities had exported="true" by default on API level 16 and lower. This inconsistency created security risks across different devices.

Primary Solution: Add Explicit android:exported Declarations

For Launcher Activities

Your main/launcher activity must have android:exported="true":

xml
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:theme="@style/AppTheme.Launcher">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

For Other Activities

Non-launcher activities should typically use android:exported="false":

xml
<activity
    android:name=".SecondaryActivity"
    android:exported="false" />

For Broadcast Receivers

Receivers that need to respond to system events (like boot completion) require android:exported="true":

xml
<receiver 
    android:name=".BootReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

For Services

Services with intent filters need explicit exported declarations:

xml
<service
    android:name=".MyService"
    android:exported="true"
    android:enabled="true" />

Security Consideration

Don't blindly set android:exported="true" for all components. Evaluate each component's purpose and only export those that genuinely need to be accessible from outside your app.

Identifying Problematic Components

When the error doesn't clearly point to a specific component in your main manifest, follow these steps:

  1. Temporarily downgrade targetSdkVersion to 30 in your build.gradle:
gradle
android {
    compileSdkVersion 31
    targetSdkVersion 30  // Temporary downgrade
    // ...
}
  1. Use Android Studio's Merged Manifest Viewer:

    • Open your AndroidManifest.xml file
    • Click the "Merged Manifest" tab at the bottom
    • Look for components with intent filters but missing android:exported attributes
  2. Check third-party dependencies - often the problematic components come from libraries that haven't been updated for Android 12 compliance.

Handling Third-Party Dependencies

If the issue comes from external libraries, you have several options:

Option 1: Override in Your Manifest

Add the component declaration to your manifest with the correct android:exported value:

xml
<activity
    android:name="com.some.library.SomeActivity"
    android:exported="false"
    tools:node="merge" />

Option 2: Create Debug-Specific Manifest

For debug-only dependencies, create a separate manifest in src/debug/AndroidManifest.xml:

xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity
            android:name="leakcanary.internal.activity.LeakActivity"
            android:exported="true"
            tools:node="merge">
            <!-- intent filters if needed -->
        </activity>
    </application>
</manifest>

Option 3: Update or Replace Libraries

Check for updated versions of your dependencies that support Android 12. If a library is abandoned, consider replacing it with a maintained alternative.

Outdated Dependencies

Some popular libraries that initially caused issues include:

  • LeakCanary versions before 2.7
  • Older analytics libraries (Flurry, StartApp)
  • Various push notification libraries

Complete Example Manifest

Here's a complete example showing proper android:exported usage:

xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <application>
        <!-- Launcher activity - exported true -->
        <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>

        <!-- Internal activity - exported false -->
        <activity
            android:name=".InternalActivity"
            android:exported="false" />

        <!-- Boot receiver - exported true -->
        <receiver
            android:name=".BootReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <!-- Internal service - exported false -->
        <service
            android:name=".InternalService"
            android:exported="false" />
    </application>
</manifest>

Common Pitfalls and Solutions

DON'T: Downgrade targetSdkVersion Permanently

While setting targetSdkVersion to 30 temporarily helps diagnose the issue, keeping it at 30 permanently avoids the requirement but prevents you from using Android 12 features and may cause compatibility issues in the future.

DO: Update All Test Dependencies

Ensure your test dependencies are also updated. For example:

gradle
androidTestImplementation 'androidx.test.ext:junit:1.1.3'

Conclusion

The Android 12 android:exported requirement is a security enhancement that prevents unintended component exposure. By:

  1. Explicitly declaring android:exported for all components with intent filters
  2. Carefully setting appropriate values (true for launcher activities and receivers needing system access, false for internal components)
  3. Addressing third-party library issues through overrides or updates

You can ensure your app complies with Android 12 requirements while maintaining security best practices.