将 Android 工程的 targetSdkVersion
从 30 (Android 11)升级到 31(Android 12)需要关注一些重要的行为变更和适配点。
主要适配要点:
适配类别 | 关键变更点 | 适配紧迫性 | 简要说明 |
---|---|---|---|
组件导出属性 | 声明了 Intent Filter 的组件必须显式设置 android:exported 属性 |
强制 | 避免组件被意外调用,提升安全性。 |
PendingIntent | 必须显式声明可变性标志 | 强制 | 指定 FLAG_MUTABLE 或 FLAG_IMMUTABLE 以明确意图。 |
前台服务 | 限制从后台启动前台服务 | 强制 | 除特定情况外,应用在后台时无法启动前台服务。 |
自定义通知 | 自定义通知视图使用系统标准模板 | 强制 | 自定义通知的内容区域不再覆盖整个通知区域,需检查布局适配性。 |
应用启动动画 | 引入新的 SplashScreen API | 推荐 | 提供一致的应用启动体验,建议替换自定义启动页。 |
隐私和安全 | 近似位置权限、麦克风和摄像头指示器、剪贴板访问提示等 | 强制/推荐 | 增强用户隐私保护,需适配新的权限模型和提示。 |
1. 组件导出属性 (android:exported)
问题 :在 Android 12 中,所有包含了 intent-filter
的 Activity 、Service 、Broadcast、Receiver 都必须显式声明 android:exported
属性,明确指示该组件是否允许被其他应用调用。
适配方案 :检查你的 AndroidManifest.xml
文件,为所有包含 <intent-filter>
的组件添加 android:exported
属性。
XML
<activity
android:name=".YourActivity"
android:exported="true"> <!-- 明确设置 exported 值 -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
<service
android:name=".YourService"
android:exported="false"> <!-- 仅限内部使用 -->
</service>
<receiver
android:name=".YourReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
注意 :android:exported="true"
表示允许外部应用调用,false
则表示不允许。缺乏此声明在 Android 12 及以上版本会导致安装失败或运行时错误,如下:

2. PendingIntent 可变性
问题 :Android 12 要求为创建的每个 PendingIntent
对象显式指定其可变性标志:FLAG_MUTABLE
或 FLAG_IMMUTABLE
。
适配方案 :检查所有创建 PendingIntent
的代码。
java
// 创建一个可变的 PendingIntent(通常用于需要被其他应用修改的 Intent)
PendingIntent mutablePendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE // 添加 FLAG_MUTABLE
);
// 创建一个不可变的 PendingIntent(安全性更高,推荐只要不需要修改 Intent 就使用此选项)
PendingIntent immutablePendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE // 添加 FLAG_IMMUTABLE
);
原则 :如果不需要让其他应用修改你的 PendingIntent
所包装的 Intent
,优先使用 FLAG_IMMUTABLE
,这样更安全。
3. 前台服务启动限制
问题 :Android 12 开始,应用在处于后台时,通常无法启动前台服务 。这是为了节省电量和管理资源。否则会抛出 ForegroundServiceStartNotAllowedException
。
适配方案:
-
评估需求 :确认是否必须在后台启动前台服务。许多后台任务可以用 WorkManager 来调度和执行。
-
使用替代方案 :优先考虑使用
WorkManager
的加急作业(Expedited Work)来处理需要立即执行的后台任务。
java
// WorkManager 示例 (使用加急作业)
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(YourWorker.class)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) // 设置加急
.build();
WorkManager.getInstance(context).enqueue(request);
- 检查例外情况:如果你的场景确实符合后台启动前台服务的少数例外条件(例如,由于用户操作,如点击通知、小部件;或者特定的系统事件回调),请确保正确配置并准备好处理可能的异常。
4. 自定义通知样式
问题 :Android 12 改变了完全自定义通知的视觉效果。系统会使用一个标准模板来装饰所有通知,自定义布局只能占据模板内指定区域,而不再是整个通知区域。
适配方案:
-
测试通知外观:务必在 Android 12 设备上测试所有自定义通知,确保布局正确显示。
-
使用标准样式 :尽可能使用系统的标准通知样式和扩展布局(如
InboxStyle
,BigPictureStyle
),它们能更好地适应不同版本。 -
提供展开式布局 :如果必须使用自定义视图,确保同时为展开状态提供布局(
setCustomBigContentView
)。
5. 应用启动画面 (Splash Screen)
问题 :Android 12 引入了统一的应用启动画面 API (SplashScreen)。系统会为所有应用默认显示一个启动画面,该画面由应用的启动图标和主题的 windowBackground
组成。
适配方案:
-
接受默认效果:如果不介意默认效果,可以不做任何改动。
-
定制启动画面 (推荐):若要自定义,请使用 Jetpack 的 SplashScreen 兼容库,它可以在 Android 12 之前和之后的版本上提供一致的体验。
-
添加依赖:
implementation "androidx.core:core-splashscreen:1.0.1"
-
定义主题,继承
Theme.SplashScreen
。 -
在
AndroidManifest.xml
中将该主题应用于启动 Activity。 -
在 Activity 中安装 Splash Screen。
6. 隐私和安全增强
Android 12 引入了多项隐私改进,部分会影响所有应用,部分仅针对 targetSdkVersion 31+的应用: