随着 Android 12 正式版 的发布,越来越多的用户将升级至最新版本。Android 12 带来大量新 API 和功能更新的同时也带来了平台兼容性的变更,我们建议开发者优先对当前应用进行测试,并进行兼容性更新。这样一来,当用户将设备更新至 Android 12 时,可确保其拥有良好的体验。
本文将重点介绍 Android 12 中最大的兼容性变更,并分享有关如何让用户顺利过渡到最新版本系统的一些建议。此外,我们还会分享一些来自领先应用的案例和建议,以帮助您了解其他开发者如何充分利用 Android 12 的功能,以及如何借鉴到自己的应用中。
如果您更喜欢通过视频了解此内容,请 点击此处 查看。
自定义通知 (仅影响 targetSdkVersion 为 31 的应用)
Android 12 更改了完全自定义通知的外观和行为,使其在视觉上保持一致且易于浏览,并为用户提供可检测到的、熟悉的通知展开状态。
△ Android 12 的通知样式
在之前,自定义通知能使用整个通知区域,并能提供自己的布局和样式。对于面向 Android 12 的应用,带有自定义内容视图的通知将不再使用整个通知区域,系统改而使用标准模板。
△ Android 12 之前和之后自定义通知可使用的区域对比
该模板确保自定义通知在所有状态下的装饰与其他通知相同,例如图标、应用名、展开和收起状态标识。该变更会影响使用自定义 Notification.Style 子类或使用 Notification.Builder 方法设置自定义内容视图的应用。如果您的应用正在使用完全自定义通知,请务必测试这类通知是否能够兼容新模板。
△ 受影响的自定义内容视图的 API
沉浸式模式下的手势导航 (影响所有应用)
Android 12 还整合了现有行为,让用户在沉浸模式下更轻松地执行手势导航命令。即使处于沉浸式模式下,系统手势也会立即响应。BEHAVIOR_SHOW_BARS_BY_TOUCH 和 BEHAVIOR_SHOW_BARS_BY_SWIPE 这两种行为现已弃用,被新的 BEHAVIOR_DEFAULT 行为所取代。BEHAVIOR_DEFAULT 行为让用户只需滑动一次即可执行手势导航,而在 Android 11 上则需要滑动两次。即使是开发全屏游戏的体验,仍可在沉浸模式下通过使用 BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE 标记来防止用户受到误触手势的影响。
△ Android 12 中沉浸式模式下的手势导航
性能相关的变更
前台服务 (仅影响 targetSdkVersion 为 31 的应用)
前台服务能让 Android 系统确保资源优先用于完成用户发起的耗时任务,但它经常被滥用。我们发现几乎一半的前台服务是从后台启动的,这导致了许多问题,包括电量会被迅速耗尽,以及用户会被意外的前台服务通知困扰等。因此从 Android 12 开始,将禁止从后台启动前台服务,并对启动前台服务作了限制。以下情况可启动前台服务:
可见的 Activity 或窗口 用户操作,如通知、小部件等等 特定的广播和回调 STICKY 类型的服务可在崩溃或由于低内存而停止运行的情况下重启
有关前台服务启动限制的完整豁免列表,请查阅 Android 开发者网站—— 前台服务。
今年早些时候,我们在 Jetpack 的 WorkManager 库中引入了加急任务。这些低延迟任务可从前台或后台调用并会立即执行。这些任务可在低电量模式下运行。我们鼓励开发者尽可能使用这些任务来替代启动前台服务。
精确闹钟权限 (仅影响 targetSdkVersion 为 31 的应用)
在大多数情况下,应用应使用粗精确度闹钟,其优势在于省电。在闹钟和计时器等特殊情况下,可使用精确闹钟。Android 12 新增了一项清单权限——SCHEDULE_EXACT_ALARM,用户可查看并控制拥有此权限的应用。此外,还新增了一个新的 API —— canScheduleExactAlarms(),您可使用此 API 来检查应用的权限状态。
通知 trampoline (Notification trampolines,仅影响 targetSdkVersion 为 31 的应用)
一些应用在处理用户点击通知的行为时,会使用广播接收器或服务等中间组件,这些组件被称为通知 trampoline,它们常常导致延迟和用户流程中断,面向 Android 12 的应用将不能从这些蹦床启动 Activity。这一新限制有助于减少从通知启动应用的延迟。我们鼓励弃用通知 trampoline 并直接从通知启动目标 Activity。举个例子,在弃用通知 trampoline 后,Google 相册应用的启动速度提高了 34%。如果您的应用使用了通知 trampoline,请使用以下 adb 命令查看用户与通知交互时所启动的组件:
$ adb shell dumpsys activity service \
com.android.systemui/.dump.SystemUIAuxiliaryDumpService
△ 使用该命令查看用户与通知交互时所启动的组件
应用链接 (仅影响 targetSdkVersion 为 31 的应用)
Android 支持应用链接的概念,它可以让 HTTP 网址直接链接到已安装的应用。这样便可完全绕过消歧对话框,通过消除用户使用过程中的分歧来改善用户体验。应用链接与深层链接的区别在于应用链接只能处理 HTTP 模式,而深层链接可以处理任何模式。
不同于以前的版本,Android 12 将始终为未验证的链接打开默认浏览器。这可能是应用链接在行为方面最重要的变更。Android 12 还引入了逐条链接验证,因此,如果存在任何服务器端集成或配置错误,将仅限于未通过验证的链接,您可以使用新 DomainVerificationManager API 检查域名验证状态,并在需要时将用户带到「设置」以便批准应用使用的域名。如需了解详情,请参阅 Android 开发者网站—— 验证 Android 应用链接。
△ 使用应用链接绕过消歧对话框直达已安装应用
兼容性框架工具
现在我们已了解 Android 12 中的新功能和变更,下面我们来看看让应用兼容的测试和工具。在 Android 11 中我们引入了兼容性框架工具以便针对变更更轻松地测试和调试应用。有了这些工具您可以单独打开和关闭某个重大变更并评估其对应用的影响。通过这种方式,您可以一次只针对一项行为变更进行隔离和测试,或轻松启用 targetSDK 对应的变更。
△ 开发者选项 > 应用兼容性变更
您可以使用开发者选项、logcat 或 adb 命令来检查当前启用的行为变更。对于每项行为变更,当应用首次调用受影响的 API 时,系统会输出一条类似这样的 logcat 消息:
D CompatibilityChangeReporter: Compat change id reported: 170668199 ;
UID 10265; state: ENABLED
△ Logcat 为某项变更的输出示例
您可以使用以下 adb 命令列出系统已知的所有兼容性变更 (包括已启用和禁用的变更) 及其当前的启用情况。列表中的每项变更都有名称、供引用的变更 ID 和启用/禁用状态。
$ adb shell dumpsys platform-compat
△ 使用 adb 命令列出系统已知的所有兼容性变更
还可以使用以下 adb 命令打开或关闭某个软件包的变更:
$ adb shell am compat enable|disable|reset <CHANGE_ID | CHANGE_NAME> <PACKAGE_NAME>
△ 使用 adb 命令设置单个应用的变更
在基本测试中无需更改 targetSdkVersion 或重新编译应用,Android 平台会自动调整其内部逻辑。由于可单独打开或关闭变更,因此可逐一进行隔离测试、调试行为变更,或禁用导致问题的单项变更。
请注意,由于只能打开或关闭可调试应用的变更。因此,如果在兼容性框架中未看到您的应用请确保在清单中将应用设置为可调试:
<application
android:debuggable="true">
△ 在清单文件中将应用设置为可调试
请记住在已签名的 Android 发布版本上,无法修改影响所有应用的变更的启用状态。Android 12 添加了新的 adb 命令来测试和验证应用的应用链接。您可使用这些命令在设备上手动验证链接,或将其添加到持续集成工具链中。
// 清除应用任何已经验证的状态:
$ adb shell pm set-app-links --package PACKAGE_NAME 0 all
// 开始验证测试:
$ adb shell pm verify-app-links --re-verify PACKAGE_NAME
// 查看测试结果:
$ adb shell pm get-app-links PACKAGE_NAME
△ 在 Android 12 中使用这些 adb 命令测试应用链接
请务必尝试使用 Android Studio Arctic Fox 进行开发和测试。我们已添加 lint 检查来帮助您发现代码可能受 Android 12 变更影响的地方。例如自定义开屏页、针对精确位置使用的粗略位置权限、媒体格式等。当然,首先要做的就是设置 Android 12 SDK。
最重要的一点,记得测试您的应用并确认其与 Android 12 的兼容性。许多开发者已完成此任务,现在是时候为这些变更做好准备并提供出色的用户体验。我们期待在 Android 12 上看到您的应用。
欢迎您 点击这里 向我们提交反馈,或分享您喜欢的内容、发现的问题。您的反馈对我们非常重要,感谢您的支持!
=10_01=: androidx navigation 怎么获取上一个页面的返回值呢?
MoYan1082: 这个数据收集有接口可以调么?
是六一啊i: 因为Box()是inline函数
孙强 Jimmy: 排版有点乱
是嗨森啦: 请问一下能读取识别文件流吗? 目测是不支持