Android 12 的 android:exported 配置问题与解决方案
问题描述
当应用程序针对 Android 12(API 级别 31)或更高版本时,如果组件包含 Intent Filter 但没有显式声明 android:exported
属性,会出现编译错误:
"Manifest merger failed with multiple errors, see logs"
具体错误信息为:
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.
这是 Android 12 引入的新安全要求,旨在防止无意中导出应用程序组件。
根本原因
从 Android 12 开始,任何包含 <intent-filter>
的 Activity、Service、BroadcastReceiver 或 ContentProvider 都必须显式声明 android:exported
属性,明确指示该组件是否可供其他应用程序访问。
解决方案
方法 1:为所有包含 Intent Filter 的组件添加 exported 属性
在 AndroidManifest.xml
中,为所有包含 <intent-filter>
的组件添加 android:exported
属性:
<!-- 启动 Activity(通常需要设置为 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>
<!-- 其他 Activity(根据需求设置为 true 或 false) -->
<activity
android:name=".OtherActivity"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
<!-- Service 组件 -->
<service
android:name=".MyService"
android:exported="false"/>
<!-- BroadcastReceiver 组件 -->
<receiver
android:name=".MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
方法 2:查找并修复第三方库的问题
如果错误来自第三方库,需要定位问题并覆盖其配置:
使用合并清单视图定位问题:
- 打开
AndroidManifest.xml
- 点击底部的 "Merged Manifest" 标签页
- 查找缺少
android:exported
属性的组件
- 打开
在应用的清单文件中覆盖库的配置:
<!-- 覆盖第三方库的 Activity 配置 -->
<activity
android:name="com.third.party.LibraryActivity"
android:exported="false"
tools:node="merge"
tools:overrideLibrary="com.third.party.library" />
<!-- 覆盖第三方库的 Receiver 配置 -->
<receiver
android:name="com.third.party.LibraryReceiver"
android:exported="false"
tools:node="merge"
tools:overrideLibrary="com.third.party.library" />
方法 3:更新测试依赖库
某些测试库(如 androidx.test)可能导致此问题,更新到最新版本:
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'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.3.3"
}
方法 4:临时降级 targetSdkVersion(不推荐)
如果急需发布应用但无法立即修复所有问题,可以临时降级:
android {
compileSdkVersion 31
defaultConfig {
targetSdkVersion 30 // 临时降级,非长久之计
// ...
}
}
WARNING
降级 targetSdkVersion 只是临时解决方案,从 2022 年开始,Google Play 要求新应用必须针对 Android 12 或更高版本。
常见问题排查
1. 如何确定哪些组件需要修复?
使用以下方法之一:
- 方法 A:查看构建日志中的详细错误信息
- 方法 B:检查
app/build/intermediates/merged_manifest/
下的合并清单文件 - 方法 C:临时将 targetSdkVersion 设为 30 以生成合并清单,然后分析问题
2. exported 应该设置为 true 还是 false?
- 设置为 true:组件可供其他应用访问(如主启动器 Activity)
- 设置为 false:组件仅供应用内部使用(大多数情况)
TIP
遵循最小权限原则,只有在确实需要与其他应用交互时才将 exported 设为 true。
代码示例
以下是包含正确 exported 配置的完整示例:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.app">
<application>
<!-- 主启动器 Activity -->
<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>
<!-- 内部使用的 Activity -->
<activity
android:name=".InternalActivity"
android:exported="false" />
<!-- 处理 deep link 的 Activity -->
<activity
android:name=".DeepLinkActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="example" />
</intent-filter>
</activity>
<!-- 内部 Service -->
<service
android:name=".MyService"
android:exported="false" />
<!-- BroadcastReceiver -->
<receiver
android:name=".MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
总结
Android 12 的 exported 要求是一项重要的安全改进,确保了开发者必须明确声明组件的可见性。通过系统性地检查所有包含 Intent Filter 的组件并正确设置 exported 属性,可以顺利解决编译错误并提高应用的安全性。
INFO
始终优先考虑更新第三方库到最新版本,因为库的维护者通常会在新 Android 版本发布后及时修复兼容性问题。