Skip to content

Android 12 的 Manifest Merger Failed 错误解决方案

问题描述

当您的应用以 Android 12(API 级别 31)或更高版本为目标平台时,可能会遇到以下构建错误:

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.

这个错误表明,在您的 Android 应用清单文件中,包含 intent filter 的组件(如 Activity、Service 或 Broadcast Receiver)没有明确声明 android:exported 属性。

什么是 android:exported 属性?

android:exported 属性决定了组件是否可以被其他应用程序访问:

  • true: 任何应用都可以通过明确的类名访问和启动该组件
  • false: 只有同一应用的组件、具有相同用户 ID 的应用或特权系统组件才能启动该组件

在 Android 12 之前,此属性的默认值根据组件类型和 Android 版本有所不同。但从 Android 12 开始,任何包含 intent filter 的组件都必须显式声明此属性。

解决方案

1. 为包含 intent filter 的组件添加 exported 属性

对于您的启动 Activity(通常包含 MAIN 和 LAUNCHER intent filter):

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>

对于 Broadcast Receiver:

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

对于 Service:

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

2. 确定正确的 exported 值

WARNING

不要盲目地为所有组件设置 android:exported="true"。应根据组件的实际用途选择合适的值。

  • 启动 Activity: 必须设置为 true,否则应用无法启动
  • 需要被系统或其他应用调用的组件: 设置为 true
  • 仅内部使用的组件: 设置为 false 以提高安全性

3. 检查依赖库中的清单文件

INFO

有时问题可能来自第三方依赖库,它们可能还没有更新以兼容 Android 12。

使用 Android Studio 的 "Merged Manifest" 功能来检查完整的合并清单:

  1. 打开 AndroidManifest.xml 文件
  2. 点击底部的 "Merged Manifest" 选项卡
  3. 查看所有合并的组件,找到缺少 android:exported 属性的组件

4. 处理第三方库的问题

如果问题来自第三方库,您可以:

方案一:在调试版本中覆盖清单设置

创建 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" />
        
        <activity
            android:name="leakcanary.internal.RequestStoragePermissionActivity"
            android:exported="false" />
    </application>
</manifest>

方案二:更新第三方库到最新版本

检查并更新所有已过时的依赖项:

gradle
dependencies {
    // 更新测试库
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    
    // 检查其他库是否有更新版本
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}

方案三:考虑替换已废弃的库

如果某个库长期未更新且不再维护,应考虑寻找替代方案。

特殊情况处理

需要 BIND 权限的服务

对于需要特定绑定权限的服务,仍需设置 exported="true"

xml
<service
    android:name=".MyAccessibilityService"
    android:exported="true"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
</service>

多 intent filter 的 Broadcast Receiver

对于包含多个 intent filter 的接收器:

xml
<receiver
    android:name=".alarms.AlarmReScheduler"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        <action android:name="android.intent.action.PACKAGE_REPLACED" />
        <!-- 针对特定设备的 action -->
        <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>

常见问题排查

  1. 确认目标 SDK 版本:确保 build.gradle 中正确设置了 targetSdkVersion

  2. 检查所有清单文件:包括主清单和依赖库的清单

  3. 使用 Merged Manifest 视图:在 Android Studio 中查看最终合并的清单

  4. 逐步排查:如果项目复杂,可以暂时将 targetSdkVersion 降级到 30 来识别问题组件

总结

Android 12 引入的 android:exported 要求是为了提高应用安全性,防止意外的组件暴露。通过正确设置此属性,不仅可以解决构建错误,还能增强应用的安全性防护。

TIP

始终遵循最小权限原则:只为需要被外部访问的组件设置 android:exported="true",其他组件应设置为 false

如果您遵循上述步骤,应该能够成功解决 Android 12 的 Manifest Merger Failed 错误,并使您的应用符合最新的 Android 平台要求。