前言
Android 12 是 2021 年 10 月公布的最新正式版本,然而很多同学示意还没有适配。针对开发者在进行版本适配过程中遇到的问题,咱们建设了 GitHub · AndroidPlatformWiki。咱们心愿站在开发者的视角,全面且粗浅地解读每个 Android 版本更新,以此建设起一个体系化的 Android 零碎适配手册。具体包含:
两个维度
依据内容相关度,咱们将从 2 个维度解读:
- 基于工夫线: 现阶段官网每年会公布一个新的版本,因而有必要以一个 Android 版本为单位,解读该版本波及的新性能与行为变更。这样能够帮忙开发同学理解新版本的更新内容,例如咱们会通过一个文档解读 Android 13 版本的更新内容与适配自查表;
- 基于内容线: 通常一个零碎功能模块会历经多个零碎版本更新才会趋于稳定,因而有必要以一个性能为单位,解读该性能的次要能力以及不同版本的变更和差别。这样能够帮忙开发同学理解该性能在不同版本上的差别,例如咱们会通过一个文档独自解读零碎告诉。
三个等级
依据故障敏感性分级,咱们将零碎变更的兼容性划分为 3 个等级:
- 强制适配 ❗: 所有利用必须适配,否则会呈现编译不通过、性能不可用或者用户体验受损等问题;
- 举荐适配 ⭐: 不强制要求适配,但适配的利用将取得更杰出的用户体验或更平安的隐衷爱护等收益;
- 已适配: 利用不须要任何改变就曾经兼容。
两类行为变更
零碎行为变更通常属于以下两种类别之一:
- 面对所有利用的行为变更: 运行在该零碎版本上的所有利用都会影响,而无论利用的 targetSDKVersion 为何。通常应该先针对这些变更进行适配和测试,这有助于用户在新版本零碎上运行你的利用时,用户体验不会受损;
- 以特定 targetSDKVersion 为指标版本的行为变更: 只有 targetSDKVersion 高于或等于零碎版本的利用会影响,通常是影响较大或适配工作量较大的变更,咱们能够了解为一个 Google 留给开发者的适配缓冲。
Android 12 适配自查表
依据故障敏感性分级,咱们将 Android 12 零碎变更的兼容性划分为 3 个等级:
- 强制适配 ❗:波及该性能的所有利用必须适配的变更,不适配的利用会呈现编译不通过、性能不可用,或者用户体验呈现肯定受损等问题;
- 举荐适配 ⭐: 不强制要求适配的变更,适配的利用具备更杰出的用户体验或更平安的隐衷爱护等;
- 已适配:利用不须要任何改变就能够兼容的变更。
以 Android 12 为指标版本的利用
类别 | 变更 | 兼容性 | 摘要 |
---|---|---|---|
1. 用户体验 | 自定义告诉外观模板对立 | 强制 ❗ | 自定义告诉的内容区域放大为自定义告诉模板内的一块区域,不再残缺笼罩告诉区域 |
画中画 (PiP) 交互改良 | 举荐 ⭐ | 优化画中画 (PiP) 模式的用户交互 | |
Toast 视图改良 | 已适配 | 零碎 Toast 视图文本最多能够显示两行,并且始终在文本旁边显示利用图标 | |
2. 平安和隐衷设置 | 新蓝牙运行时权限(新) | 举荐 ⭐ | 引入一些新运行时权限,用于更好地治理利用于左近蓝牙设施的连贯,而无需申请地位信息权限 |
传感器采样率限度 | 已适配 | 零碎会限度某些挪动传感器和地位传感器的数据的刷新率 | |
利用休眠改良 | 已适配 | 扩大利用休眠机制 | |
数据拜访审核中的归因标记改良 | 强制 ❗ | 归因标记必须在 Manifest 文件中申明 | |
ADB 备份限度 | 已适配 | adb backup 导出的数据不再默认蕴含利用数据 | |
显式指定组件 exported 属性 | 强制 ❗ | 申明了 <intent-filter> 过滤器的组件必须显式设置 android:exported 属性 | |
显式指定 PendingIntent 可变性 | 强制 ❗ | PendingIntent 必须显式申明一个可变性标记 | |
检测不平安的嵌套 Intent 启动 | 已适配 | StrictMode 会检测不平安的嵌套 Intent 启动 | |
3. 性能和电池 | 准确的闹钟权限(新) | 强制 ❗ | 设置 AlarmManager 精准闹钟的利用必须在 Manifest 中申明权限 |
前台服务启动限度 | 强制 ❗ | 除了多数状况外,禁止利用从后盾启动前台服务 | |
告诉 trampoline 限度 | 强制 ❗ | 禁止从告诉 trampoline 间接启动指标 Activity |
所有利用
类别 | 变更 | 兼容性 | 摘要 |
---|---|---|---|
4. 用户体验 | Material You 设计语言(新) | 已适配 | 新的设计语言 |
富媒体内容插入(新) | 举荐 ⭐ | 利用能够从对立的地位承受任何起源(剪贴板粘贴、键盘输入或拖放操作)的内容 | |
反对 AVIF 图片(新) | 举荐 ⭐ | 反对 AVIF 格局图片 | |
利用启动动画 API SplashScreen(新) | 强制 ❗ | 反对定制利用启动转场动画 | |
Widget 桌面小部件改良 | 举荐 ⭐ | 改良 Widgets 外观和行为 | |
图形 API 改良 | 举荐 ⭐ | 新增图形成果 | |
OverScroll 适度滑动动画改良 | 已适配 | 适度滑动动画改为拉伸和反弹成果 | |
告诉改良 | 举荐 ⭐ | 减少新的告诉款式和平安保障 | |
HTTP 深度链接解析改良 | 已适配 | 调整了 HTTP Intent 的默认解析行为 | |
全屏模式的手势导航改良 | 举荐 ⭐ | 减少了一次交互即可执行手势导航的模式 | |
屏幕尺寸 API 变更 | 强制 ❗ | 针对适配每种设配上获取屏幕尺寸的需要,零碎引入了新 API | |
多窗口模式标准化 | 强制 ❗ | 在大屏设施中,零碎会为所有 Activity 启用多窗口模式 | |
提早展现前台服务告诉 | 已适配 | 除了非凡状况外,前台服务告诉会提早 10 s 显示 | |
activity 生命周期改良 | 已适配 | 批改根 Activity 的返回行为 | |
Surface 帧率切换改良 | 举荐 ⭐ | 引入强制切换帧率的 API | |
5. 平安和隐衷设置 | 隐衷信息中心(新性能) | 举荐 ⭐ | 隐衷信息中心以一个时间轴的形式显示过来工夫内所有利用对于敏感信息的拜访状况 |
反对只授予粗略地位权限(新) | 强制 ❗ | 用户能够只授予利用含糊地位权限 | |
麦克风和摄像头切换开关(新) | 已适配 | 用户能够通过全局切换开关停用整台设施上的摄像头或麦克风权限 | |
麦克风和摄像头批示标示(新) | 已适配 | 利用应用麦克风或相机时,状态栏会有图标标记。 | |
剪贴板拜访提醒(新) | 已适配 | 利用首次从另一个利用拜访剪辑数据时,会弹出一个音讯框音讯 | |
暗藏利用叠加窗口(新) | 举荐 ⭐ | 利用的窗口可见时能够暗藏所有可见的零碎级悬浮窗口 | |
利用无奈关闭系统对话框 | 强制 ❗ | 除了非凡状况外,禁止利用尝试关闭系统对话框 | |
屏蔽不信赖的触摸事件 | 强制 ❗ | 屏蔽从不同利用的窗口传递的事件 | |
6. 性能和电池 | 利用待机分区改良 | 已适配 | 引入了一个新的受限待机分区 |
第 1~3 节介绍的是以 Android 12 为指标版本的利用行为变更和新性能更新,我将这部分更新总结为 3 局部:
- 1、用户体验(以 Android 12 为指标版本)
- 2、平安和隐衷设置(以 Android 12 为指标版本)
- 3、性能和电池(以 Android 12 为指标版本)
1. 用户体验(以 Android 12 为指标版本)
1.1 自定义告诉外观模板对立
Android 零碎告诉能够分为两类款式:规范告诉 + 自定义告诉
- 规范告诉:规范告诉是指基于
NotificationCompat.Builder#setContentTitle()
等模板 API 构建告诉,最终会依照零碎预置的视图模板展现。例如:
- 自定义告诉:自定义告诉是指基于
NotificationCompat.Builder#setCustomContentView()
等 API 构建的告诉,最终会依照开发者自定义的的布局展现,而不会依照规范告诉模板展现。
从 Android 12 零碎开始,零碎标准了自定义告诉的外观和行为,自定义告诉的内容区域放大为自定义告诉模板内的一块区域,不再残缺笼罩告诉区域。因而,如果你的利用应用了自定义告诉,则须要进行必要的测试和调整:
- 布局调整:因为内容区域放大了,须要调整并测试告诉布局;
- 设置展开式告诉:因为所有告诉都是可开展的,所以须要调用
NotificationCompat.Builder#setCustomBigContentView()
设置开展后布局,确保开展和收起状态统一。
下图是对立的自定义告诉模板:
能够看出,这次改变是 Google 心愿自定义告诉可能出现绝对统一的感观体验,以及缩小不同设施上产生的兼容性问题。
1.2 画中画 (PiP) 交互改良
画中画模式是 Android 8.0 中引入的一种多窗口模式,最罕用于视频播放 Activity,可能实现在视频播放过程中关上其余利用,而不退出中断以后视频。目前支流的音视频 App 都反对画中画模式,你能够在零碎设置中搜寻“画中画”查看。这次改变是 Google 对画中画模式的用户交互进行优化,具体参考资料:
- 对画中画的反对 —— 官网文档
- Android 12 画中画改良 —— 官网文档
1.3 Toast 视图改良
在 Android 12 中,零碎 Toast 视图文本最多能够显示两行,并且始终在文本旁边显示利用图标。相干材料:音讯框概览
2. 平安和隐衷设置(以 Android 12 为指标版本)
2.1 新蓝牙运行时权限(新性能)
Android 12 零碎引入了新的运行时权限 BLUETOOTH_SCAN、BLUETOOTH_ADVERTISE 和 BLUETOOTH_CONNECT 权限,用于更好地治理利用于左近蓝牙设施的连贯。
在低版本中,利用与左近蓝牙设施连贯须要用户授予 ACCESS_FINE_LOCATION
准确地位权限,这其实是不合理的设计,因为用户很难了解为什么蓝牙连贯会跟地位信息无关。从 Android 12 零碎开始,ACCESS_FINE_LOCATION 准确地位权限是可选项,只有利用不会通过蓝牙推导物理地位信息,就不再须要申请。如果不会,你须要在 Manifest 中显式做出 usesPermissionFlags
申明:
<manifest>
<!-- Include "neverForLocation" only if you can strongly assert that
your app never derives physical location from Bluetooth scan results. -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
...
</manifest>
-
新蓝牙权限体系(以 Android 12 为指标版本):
- BLUETOOTH_SCAN:容许搜寻左近蓝牙设施;
- BLUETOOTH_ADVERTISE:容许以后设施裸露给其余蓝牙设施;
- BLUETOOTH_CONNECT:容许以后设施连贯其余蓝牙设施;
- ACCESS_FINE_LOCATION(可选):容许由蓝牙信息推导设施地位信息。
-
旧蓝牙权限体系:
- BLUETOOTH:容许与蓝牙相干的交互;
- ACCESS_FINE_LOCATION(必选):容许由蓝牙信息推导设施地位信息,在 Android 9 或以下版本,能够用 ACCESS_COARSE_LOCATION 代替。
另外,BLUETOOTH_SCAN 等权限是 NEARBY_DEVICES 左近设施权限组的一部分。申请该权限组的权限,权限授予对话框会提醒用户批准拜访左近的设施。
能够看出,这次的改变 Google 是心愿连贯蓝牙设施的权限授予可能给用户更精准的权限性能形容。
相干材料:
- 蓝牙概览 —— 官网文档
- 蓝牙权限 —— 官网文档
2.2 传感器采样率限度
大多数 Android 设施都有内置传感器,用来测量静止、屏幕方向和各种环境条件,这些传感器可能提供高度准确的原始数据。为了爱护无关用户的潜在敏感信息,Android 12 零碎会限度某些挪动传感器和地位传感器的数据的刷新率。
相干材料:传感器概览 —— 官网文档
2.3 利用休眠改良
Android 11 引入了利用休眠机制,如果用户有几个月没有与利用交互,那么零碎会将利用置于休眠 / 蛰伏状态,Android 12 扩大了利用休眠机制:
- Android 11:重置已授予的运行时敏感权限;
- Android 12:重置已授予的运行时敏感权限;无奈从后盾运行工作;无奈接管推送告诉;利用缓存文件会被删除。
相干材料:利用休眠 —— 官网文档
2.4 数据拜访审核中的归因标记改良
Android 11 引入了数据拜访审核 API,开发者能够在利用拜访用户隐衷数据的代码地位减少归因标记,并通过注册 AppOpsManager.OnOpNotedCallback
监听。这个性能提供了对调用隐衷数据的监听,无论是应用层还是依赖库中的代码,只有拜访到私密数据(危险权限)都会回调。从 Android 12 零碎开始,归因标记必须在 Manifest 文件中申明,例如:
<manifest ...>
<!-- The value of "android:tag" must be a literal string, and the
value of "android:label" must be a resource. The value of
"android:label" should be user-readable. -->
<attribution android:tag="sharePhotos"
android:label="@string/share_photos_attribution_label" />
...
</manifest>
相干材料:数据拜访审核 —— 官网文档
2.5 ADB 备份限度
为了爱护公有利用数据,Android 12 变更了 adb backup
命令的默认行为,adb backup 导出的数据不再默认蕴含利用数据。如果开发阶段须要依赖于 adb backup 导出的利用数据,能够将 Manifest 文件中将 android:debuggable 设置为 true 来导出利用数据。
2.6 显式指定组件 exported 属性
组件属性 android:exported
用于设置该组件是否反对其余利用交互,exported 为 false 示意不容许该组件被其余利用启动。个别 exported 属性默认为 false,除非组件申明了 <intent-filter>
过滤器(即反对隐式启动),则 exported 属性默认为 true。从 Android 12 零碎开始,申明了 <intent-filter> 过滤器的组件必须显式设置 android:exported 属性。例如:
<service android:name="com.example.app.backgroundService"
android:exported="false">
<intent-filter>
<action android:name="com.example.app.START_BACKGROUND" />
</intent-filter>
</service>
否则,在编译利用时就会有报错:
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 Gradle 插件尽管能够编译胜利,但装置时会报错:
Installation did not succeed.
The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE
能够看出,这次改变背地的理念是“不要置信默认值”,因为不合乎预期的默认值会产生更重大的危险。举个例子,因为开发者的忽略,一个本来不容许内部利用启动的组件未显式申明 android:exported=“false”,而正好该组件申明了 <intent-filter> 过滤器,那么就因为默认值的影响的产生了一个平安危险。而强制开发者对申明 <intent-filter> 过滤器的组件显式申明 android:exported 的值,就能够防止了默认值的平安危险。同样的情理在对接内部零碎时,也不要置信默认值,例如网络申请参数的默认值,能传的就传。
2.7 显式指定 PendingIntent 可变性
为了使 PendingIntent 的解决更加平安,Android 12 要求 PendingIntent 必须显式申明一个可变性标记即 FLAG_MUTABLE 或 FLAG_IMMUTABLE。在此之前,PendingIntent 默认是可变的。
2.8 检测不平安的嵌套 Intent 启动
Android 12 引入了一项 StrictMode
查看规定,用于检测不平安的嵌套 Intent 启动。StrictMode 模式大家很相熟了,这里解释下为什么嵌套 Intent 启动是不平安的。
举个例子,开发者的预期成果是 Client App 申请 Provider App 的一个服务,并且心愿在申请完结后回调到 Client App 的 ClientCallbackActivity。那么,最间接的办法是将启动 ClientCallbackActivity 的 Intent 当作参数嵌套到启动 ApiService 的 Intent 里。例如:
乍看起来没有问题,但其实这种实现形式存在两个荫蔽的平安危险:
- Client App:因为 ClientCallbackActivity 是从另一个利用 Provider App 启动的,因而它必须裸露为 exported。这意味着除了 Provider App 外,设施上其余歹意的利用也能够启动 ClientCallbackActivity;
- Provider App:因为嵌套的 Intent 是在 Provider App 的上下文中启动的,因而歹意利用 Attacker App 能够将 Provider App 的任何一个 Activity 嵌套其中,即便启动的是公有的非 exported 的 Activity,这让 Provider App 防不胜防。
解决办法是应用 PendingIntent 代替嵌套 Intent,PendingIntent 是 Intent 的包装容器,也相似于一个嵌套 Intent。然而,很多小伙伴简略地认为 PendingIntent 只是提早待处理的 Intent,两者只有工夫维度的区别,这是全面的。
PendingIntent 的最次要的作用是受权内部利用以本利用的身份执行应用嵌套的 Intent。有点拗口哈,在咱们这个例子里,就是 Client App 将启动 ClientCallbackActivity 的 Intent 裸露给 Provider App 后,但 Provider App 在应用 PendingIntent 时,零碎会以 Client App 的上下文身份来应用嵌套的 Intent。
PendingIntent pendingIntent = PendingIntent.getActivity(application, 0, resultIntent, 0);
当初,咱们再回顾下还有没有危险:
- Client App:因为 PendingIntent 应用 Client App 的身份应用嵌套的 Intent,那么 ClientCallbackActivity 不再须要裸露为 exported;
- Provider App:因为 PendingIntent 应用 Client App / Attacker App 的身份应用嵌套的 Intent,而它们是没有权限拜访 Provider App 非 exported 的 ApiSensitiveActivity 的。
相干材料:Android 嵌套 Intent —— 官网博客文章
3. 性能和电池(以 Android 12 为指标版本)
3.1 准确的闹钟权限(新性能)
Android 12 零碎引入了新的权限 android.permission.SCHEDULE_EXACT_ALARM
,设置 AlarmManager 精准闹钟的利用必须在 Manifest 中申请 SCHEDULE_EXACT_ALARM 权限。此外,还新增了一个新的 API —— canScheduleExactAlarms()
,用于查看利用的精准闹钟权限状态。
相干材料:设置反复闹钟工夫
3.2 前台服务启动限度
Android 12 对利用从后盾启动前台服务的行为做出限度,除了 后盾启动限度的豁免 等多数状况外,如果利用尝试在后盾运行时启动前台服务,零碎会抛出 ForegroundServiceStartNotAllowedException
异样。利用能够应用 JobScheduler 中新引入的 加急作业 (expedited job) 来代替之前的做法。
提醒:如果一个利用调用
Context.startForegroundService()
以启动另一个利用领有的前台服务,则这些限度仅实用于两个利用都针对 Android 12 或更高版本的状况。
3.3 告诉 trampoline 限度
告诉 trampoline (蹦床) 是指利用播送接收器或服务间接启动指标 Activity(用户与告诉交互后,利用先启动服务或播送接收器作为中介,再去启动 指标 Activity)。Android 12 系统对告诉 trampoline 做出限度,当利用尝试从告诉 trampoline 启动 Activity,零碎会拦挡该启动行为:
Indirect notification activity start (trampoline) from PACKAGE_NAME, \
this should be avoided for performance reasons.
如果你的利用应用了告诉 trampoline,那么你须要切换为惯例的 PendingIntent 形式。
第 4~6 节介绍的是针对所有利用的利用行为变更和新性能更新,我将这部分更新总结为 3 局部:
- 4、用户体验(所有利用)
- 5、平安和隐衷设置(所有利用)
- 6、性能和电池(所有利用)
4. 用户体验(所有利用)
4.1 Material You 设计语言(新性能)
Android 12 引入了一种名为 Material You 的新设计语言(对 Material Design 的再倒退),可帮忙构建更具个性化、更精美的利用。
4.2 富媒体内容插入(新性能)
Android 12 零碎引入了一个对立 API,使得利用能够从对立的地位承受任何起源(剪贴板粘贴、键盘输入或拖放操作)的内容。例如:
相干材料:接管富媒体内容 —— 官网文档
4.3 反对 AVIF 图片(新性能)
Android 12 引入了对应用 AV1 图片文件格式 (AVIF) 的图片的反对。AVIF 是一种应用 AV1 编码的图片和图片序列的容器格局。AVIF 利用了视频压缩的帧内编码内容。与以前的图片格式(例如 JPEG)相比,这种格局可显著晋升雷同文件大小下的图片品质。
相干材料:AVIF has landed —— Jake Archibald 著
4.4 利用启动动画 API SplashScreen(新性能)
从 Android 12 零碎开始,所有利用的冷启动和温启动期间,零碎会应用新的 SplashScreen API 来启动利用启动动画。除了平台 API 外,Google 还提供了兼容库 API:androidx.core.splashscreen。
在 SplashScreen API 之前,咱们通常是利用 SplashActivity 的背景图 android:windowBackground
来实现利用启动转场成果,这个大家都很相熟了。如果你不做任何适配,那么依据你配置的 windowBackground 资源值,在 Android 12 上会有不同的成果:
- windowBackground 采纳
@color/ 单色
,则零碎会应用该单色和利用的启动图标来形成启动成果,这可能与预期成果不符; - windowBackground 采纳
@drawable/ 图片
,则零碎会持续应用该图片来形成启动成果,这个体验与低版本零碎统一。
因而,如果你的利用采纳的是 windowBackground 为图片资源的形式,那么你不适配也没有问题。须要降级启动成果的话,举荐参考以下材料:
- 启动画面 —— Android 官网文档
- Jetpack 新成员 SplashScreen:打造全新的 App 启动画面 —— TechMerger 著
能够看出,这次改变 Google 是心愿晋升下利用启动时的转场体验,同时也给予开发者更多自定义的设想空间。
4.5 Widget 桌面小部件改良
Android 12 改良了现有的 Widgets API,让它们更实用、更好看,且更易于发现。相干改变详见以下材料:
相干材料:
- 利用 Widget 概览 —— 官网文档
- Android 12 Widget 改良 —— 官网文档
- 发明有限可能 | 在 Android 12 中应用 widget —— 官网博客文章
- 更新您的 widget 以适配 Android 12 —— 官网博客文章
4.6 图形 API 改良
- 圆角:Android 12 引入了新的圆角 API RoundedCorner
和 WindowInsets.getRoundedCorner(int position),能够提供给 View 实现圆角成果; -
滤镜:Android 12 增加了新的滤镜 API RenderEffect 能够给 View 实现常见的图片成果(如毛玻璃、色彩滤镜、Android 着色器成果及更多成果)。
view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, SHADER_TILE_MODE))
4.7 OverScroll 适度滑动动画改良
Android 12 批改了可滚动控件在边缘适度滑动(OverScroll)的动画成果,从低版本的边缘发光成果批改为拉伸和反弹成果。这个边缘适度滑动成果是能够敞开的,有两种办法:
- 设置
android:overScrollMode=”never”
- 设置
View#setOverScrollMode(View.OVER_SCROLL_NEVER)
4.8 告诉改良
- 电话告诉:从 Android 12 零碎开始,新增了新的电话告诉款式 Notification.CallStyle;
- 丰盛图片反对:从 Android 12 零碎开始,利用能够在 MessagingStyle() 告诉中提供动画图片,来丰盛利用的告诉体验。此外,利用当初还能够让用户在从告诉栏回复音讯时发送图片音讯;
- 设施解锁保障:从 Android 12 零碎开始,利用能够通过 setAuthenticationRequired(true),要求零碎在执行告诉的 PendingIntent 前先要求用户解锁设施,这对于敏感操作减少了一层平安保障。
4.9 HTTP 深度链接解析改良
Android 零碎反对通过 Deep Link 或 Android App Link 将深度链接与利用行为关联,实际中采纳的链接基于 URI 格局,例如:
从 Android 12 零碎开始,零碎调整了 HTTP Intent 的默认解析行为。在低版本中,如果 HTTP 链接未命中任何 Deep Link / App Link 的匹配规定,那么零碎会关上利用抉择对话框;而当初零碎会间接通过默认浏览器关上链接(因为该链接自身是一个可拜访的网址)
相干材料:
- Android Deep Link 深度链接,看看你在第几层?
- 解决 Android 利用链接 —— 官网文档
4.10 全屏模式下的手势导航改良
全屏模式是指利用最大限度地利用屏幕空间来展现内容,让用户获得最佳体验,常见场景例如视频、游戏、演示文稿等。
全屏模式会暗藏状态栏、导航栏等零碎栏,意味着用户无奈轻松与零碎栏交互,因而零碎定义了以下全屏模式下的零碎栏行为,应用 WindowInsetsControllerCompat.setSystemBarsBehavior 设置:
- BEHAVIOR_SHOW_BARS_BY_TOUCH 模式,当用户点击屏幕任何地位后,会从新显示零碎栏。这种模式适宜于用户不会与屏幕进行大量互动的场景;
- BEHAVIOR_SHOW_BARS_BY_SWIPE 模式,当用户从暗藏零碎栏的边缘滑动时,会显示零碎栏。例如从屏幕底部边缘向上滑动,会从新显示零碎导航栏。这种模式适宜于用户须要与屏幕进行大量交互的场景,例如游戏、浏览等,应用这种用意更强的手势可能防止零碎栏交互与利用交互抵触;
- BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE 模式,当用户从暗藏零碎栏的边缘滑动时,会暂时性地显示零碎栏,并期待一小段时间后主动从新暗藏。零碎栏会并不会挤压利用内容,而是以半透明的形式笼罩在利用下层。
Android 12 零碎整合了现有模式,BEHAVIOR_SHOW_BARS_BY_TOUCH 和 BEHAVIOR_SHOW_BARS_BY_SWIPE 这两种行为现已弃用,新增了 BEHAVIOR_DEFAULT 行为。
- BEHAVIOR_DEFAULT 模式:当用户从暗藏零碎栏的边缘滑动时,会显示零碎栏,这一点与 BEHAVIOR_SHOW_BARS_BY_SWIPE 相似。最次要的是,全面屏导航手势能够间接失效,不论零碎导航栏是否可见。换句话说,BEHAVIOR_DEFAULT 行为让用户只需滑动一次即可执行手势导航,而在 Android 11 上则须要滑动两次。
相干材料:启用全屏模式
4.11 屏幕尺寸 API 变更
Android 11 零碎废除了 Display.getSize & Display.getMetrics,并在 Android 12 中持续废除了 Display.getRealSize & Display.getRealMetrics。Android 设施有许多不同的形状(例如大屏设施、平板电脑和可折叠手机),为了针对适配每种设施上获取屏幕尺寸的需要,零碎引入了 WindowMetrics API。
- 平台 API:WindowMetrics
- 兼容库 API:WindowManager
4.12 多窗口模式标准化
Android 7 零碎引入了多窗口模式,容许同时在屏幕上显示多个利用,目前一共有 3 种多窗口模式:
- 分屏模式:以左右并排或高低并排显示两个利用;
- 画中画模式:以叠加的小窗口显示利用;
- 自在窗口模式:以可挪动且可调整显示尺寸的窗口显示利用;
从 Android 12 零碎开始,多窗口模式将成为大屏设施上的规范行为,大屏设施下 Activity 的 resizeableActivity
配置将被疏忽。具体如下:
- Android 7:手机设施反对分屏模式,电视设施反对画中画模式,更大尺寸的设施制造商能够抉择启用自在窗口模式。开发者能够设置 android:resizeableActivity=”false”禁用多窗口模式,确保 Activity 始终以独占屏幕的形式显示;
- Android 8:手机设施也反对画中画模式;
- Android 12:在小屏设施(sw < 600dp)设施中,零碎依据 resizeableActivity 配置确定该 Activity 是否启用多窗口模式,在大屏设施中,零碎会疏忽 resizeableActivity 配置,为所有 Activity 启用多窗口模式。在此之前,用户要操作的 Activity 不反对多窗口的话,用户只能先退出窗口,再回来,体验就中断了。
能够看出,这次改变 Google 是心愿大屏设施下的多窗口模式成为规范行为,实现多窗口模式下的体验闭环。
4.13 提早展现前台服务告诉
前台服务(startForegroundService 启动的服务)会显示一个零碎告诉,以便让用户利用正在执行工作并且耗费系统资源,即便该利用曾经退出到后盾。从 Android 12 零碎开始,前台服务告诉会提早 10 s 显示,除非一些须要立刻显示告诉的服务。
以下是立刻显示告诉的状况:
- 1、前台服务告诉调用
NotificationCompat.Builder#setForegroundServiceBehavior(FOREGROUND_SERVICE_IMMEDIATE)
批改了显示行为; - 2、前台服务告诉调用
NotificationCompat.Builder#addAction()
配置了可操作按钮; - 3、前台服务告诉调用
NotificationCompat.Builder#setCategory()
配置为 CATEGORY_CALL、CATEGORY_NAVIGATION 或 CATEGORY_TRANSPORT; - 4、前台服务的 foregroundServiceType 取值 mediaPlayback、mediaProjection 或 phoneCall。
能够看出,这次改变 Google 是心愿简化短期运行的前台服务的用户感知,既然服务很快就进行了,就没有必要用告诉让用户留神到。
相干材料:
- 前台服务 —— 官网文档
4.14 activity 生命周期改良
从 Android 12 开始,零碎批改了 Activity Task 根 Activity 在解决”返回键“时的默认行为。在旧版本中,返回键会执行 finish Activity,而从 Android 12 开始会将 Task 工作栈切换到后盾。尔后,用户返回利用将执行热启动,利用的热启动简略得多,零碎的工作只是将 Activity 复原到前台。
Activity.java
public void onBackPressed() {if (mActionBar != null && mActionBar.collapseActionView()) {return;}
FragmentManager fragmentManager = mFragments.getFragmentManager();
if (!fragmentManager.isStateSaved() && fragmentManager.popBackStackImmediate()) {return;}
if (!isTaskRoot()) {
// If the activity is not the root of the task, allow finish to proceed normally.
finishAfterTransition();
return;
}
// 以上 Android 12 与旧版本雷同,差异在上面这句:try {
// Android 11
// Inform activity task manager that the activity received a back press
// while at the root of the task. This call allows ActivityTaskManager
// to intercept or defer finishing.
ActivityTaskManager.getService().onBackPressedOnTaskRoot(mToken,
new IRequestFinishCallback.Stub() {public void requestFinish() {mHandler.post(() -> finishAfterTransition());
}
});
// Android 12
// Inform activity task manager that the activity received a back press while at the
// root of the task. This call allows ActivityTaskManager to intercept or move the task
// to the back.
ActivityClient.getInstance().onBackPressedOnTaskRoot(mToken,
new RequestFinishCallback(new WeakReference<>(this)));
} catch (RemoteException e) {finishAfterTransition();
}
}
能够看出,这次的改变 Google 心愿通过”返回 键“退出的利用,可能更快地从热启动复原利用,而不是从冷启动或温启动重启利用。
4.15 Surface 帧率切换改良
Android 11 零碎引入了一个 Surface 帧率切换 API setFrameRate()
,但这个 API 并不总是会失效。因为不反对无缝切换帧率的屏幕在切换帧率时会有一两秒的黑屏,所以零碎会对这一行为做拦挡。如果屏幕不反对无缝切换,即便利用调用 setFrameRate() 仍然会持续应用原来的帧率。
Android 12 零碎引入了强制切换帧率的 API,这对于长视频内容的帧率切换更有劣势,因为适合帧率带来的体验晋升曾经超过了不反对无缝切换带来的体验损失。
// 查看是否反对无缝切换帧率
val refreshRates = this.display?.mode?.alternativeRefreshRates
val willBeSeamless = Arrays.asList<FloatArray>(refreshRates).contains(newRefreshRate)
// 切换帧率,即便屏幕不反对无缝过渡
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
- CHANGE_FRAME_RATE_ALWAYS:总是切换帧率,即便屏幕不反对无缝过渡;
- CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS:仅在屏幕反对无缝过渡时切换帧率(旧版本行为)。
5. 平安和隐衷设置(所有利用)
5.1 隐衷信息中心(新性能)
Android 12 零碎在零碎设置中引入了隐衷信息中心性能,能够让用户更好地理解利用正在拜访数据的行为。隐衷信息中心以一个时间轴的形式显示过来工夫内所有利用对于麦克风、摄像头或地位等敏感信息的拜访状况。
另外,零碎定义了一个新的 Intent 操作 ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD,能够从隐衷信息中心中向用户解释为什么利用须要拜访这些隐衷信息。要反对此性能,利用须要定义一个 Activity 并申明 IntentFilter 关联到此 Action 上,例如:
<!-- android:exported required if you target Android 12. -->
<activity android:name=".DataAccessRationaleActivity"
android:permission="android.permission.START_VIEW_PERMISSION_USAGE"
android:exported="true">
<!-- VIEW_PERMISSION_USAGE shows a selectable information icon on
your app permission's page in system settings.
VIEW_PERMISSION_USAGE_FOR_PERIOD shows a selectable information
icon on the Privacy Dashboard screen. -->
<intent-filter>
<action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
<action android:name="android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD" />
<category android:name="android.intent.category.DEFAULT" />
...
</intent-filter>
</activity>
相干材料:解释对比拟敏感信息的拜访权限
5.2 反对只授予粗略地位权限(新性能)
Android 零碎反对两个精度级别的地位信息,并且别离对应一个权限。尽管有两个精度级别的权限,然而因为它们处于同一个权限组中,所以利用只有申请授予其中一个权限,另一个权限就主动授予了。
- 粗略地位:准确到 3 平方公里的地位值,申请 ACCESS_COARSE_LOCATION 权限能够取得;
- 准确地位:准确到 50 米以内的地位值,申请 ACCESS_FINE_LOCATION 权限能够取得。
然而,从 Android 12 零碎开始,这一规定不再成立了。从 Android 12 零碎开始,用户能够只授予利用含糊地位 ACCESS_COARSE_LOCATION 权限,即便利用申请的是准确地位 ACCESS_FINE_LOCATION 权限。
举个例子,咱们通过以下代码申请 ACCESS_FINE_LOCATION 权限,在 Android 12 零碎上的权限申请弹窗会给用户两个选项:Precise 准确地位
和 Approximate 粗略地位
。如果用户抉择授予粗略地位,那么最终利用取得的权限反而是 ACCESS_COARSE_LOCATION 权限,而不是一开始申请的 ACCESS_FINE_LOCATION 权限,并且利用也只能获取粗略地位信息。
val locationPermissionRequest = registerForActivityResult(ActivityResultContracts.RequestPermission()
) { isGrant ->
Log.i("权限","isGrant: $isGrant")
if (PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {Log.i("权限", "ACCESS_COARSE_LOCATION is Grant")
}
if (PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) {Log.i("权限", "ACCESS_FINE_LOCATION is Grant")
}
}
findViewById<View>(R.id.tv).setOnClickListener {locationPermissionRequest.launch( Manifest.permission.ACCESS_FINE_LOCATION)
}
输入日志:
I/ 权限: isGrant: false
I/ 权限: ACCESS_COARSE_LOCATION is Grant
那么从 Android 12 开始,你在申请地位权限时就要留神以下问题,稍不留神就呈现兼容问题了:
-
申请地位权限时要同时申请 ACCESS_FINE_LOCATION 权限和 ACCESS_COARSE_LOCATION 权限,如果利用只申请 ACCESS_FINE_LOCATION 权限,零碎会间接疏忽该申请。如果利用以 Android 12 或更高版本为指标版本,零碎会在 logcat 中提醒谬误:
ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION.
提醒:我在 Pixel 模拟器上实测并没有呈现文档形容的”疏忽申请“和”报错提醒“,不过最好还是依照官网文档解决吧。
- 即便用户曾经授予了准确地位权限,用户仍然能够进入零碎设置中间接批改到粗略地位权限,批改后零碎会主动杀死过程。
- 为了更好地尊重用户隐衷,尽量只申请 ACCESS_COARSE_LOCATION 权限,因为粗略地位信息曾经能满足大多数利用场景。仅申请 ACCESS_COARSE_LOCATION 权限时,受权弹窗只有一个选项:
- 如果你的利用场景的确须要申请 ACCESS_FINE_LOCATION 权限,那么你能够再次同时申请 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 权限。因为之前用户曾经授予过粗略地位权限,这次的零碎弹窗会变成询问是否降级到准确地位权限:
- 最初一个问题,怎么确定利用场景时须要准确地位还是粗略地位呢?其实并不是依附纯主观判断,这块是有行业标准的。在咱们之前探讨的 还在见招拆招?先看懂 APP 个人信息爱护治理机制 中,提到过一个规范 个人规范《APP 收集应用个人信息最小必要评估标准》共 17 项。其中对于地位信息的获取有明确的规范和案例,例如:
有小伙伴发现局部 Android 12 零碎的手机上,申请地位权限的行为跟低版本没有区别,这是因为有些厂商零碎还没有齐全实现这个性能。以小米 MIUI 13.0.5.0 为例,含糊定位性能须要关上
零碎设置 - 隐衷爱护实验室 - 含糊定位
选项能力启用。而且我在该零碎上实测后,发现即便用户只授予 ACCESS_COARSE_LOCATION 权限,另一个 ACCESS_FINE_LOCATION 权限也会同时授予,这个就离谱了,怪不得还在实验室。
能够看出,这次的改变是 Google 心愿疏导开发者尽量应用低精度的地位信息,进步对用户隐衷的爱护度。
相干材料:
- 申请地位权限 —— 官网文档
- 申请利用权限 —— 官网文档
- 解释对比拟敏感信息的拜访权限 —— 官网文档
5.3 麦克风和摄像头切换开关(新性能)
从 Android 12 零碎开始,用户能够通过一个全局切换开关,停用整台设施上的摄像头或麦克风权限。当利用申请摄像头或麦克风权限时,零碎有弹窗提醒。这个切换开关在不同厂商零碎上的体现不一样,比方小米零碎是放在 手机关机 - 隐身模式
。
5.4 麦克风和摄像头批示标示(新性能)
从 Android 12 开始,当利用应用麦克风或相机时,在状态栏会有图标标记。
5.5 剪贴板拜访提醒(新性能)
在 Android 12 及更高版本中,当某个利用首次调用 getPrimaryClip 以 从另一个利用拜访剪辑数据 ”) 时,会弹出一个音讯框音讯,提醒用户利用存在拜访剪贴板的行为。
5.6 暗藏利用叠加窗口(新性能)
Android 12 零碎引入了暗藏 TYPE_APPLICATION_OVERLAY 窗口的性能。申明 HIDE_OVERLAY_WINDOWS 权限后,利用能够调用 setHideOverlayWindows 指明当利用的窗口可见时暗藏所有可见的 TYPE_APPLICATION_OVERLAY 窗口。例如在显示敏感页面(如交易)时,利用能够抉择暗藏其余悬浮窗。
5.7 利用无奈关闭系统对话框
为了增强用户与利用和零碎互动时的管制,从 Android 12 零碎开始,弃用了 ACTION_CLOSE_SYSTEM_DIALOGS Intent 操作,当利用应用尝试关闭系统对话框时,除了 一些非凡状况 之外,零碎会进行拦挡:
- 以 Android 12 或更高版本为指标版本:零碎会抛出 SecurityException;
-
以 Android 11 或更低版本为指标版本:零碎不会执行 Intent,并在 logcat 提醒:
E ActivityTaskManager Permission Denial: \ android.intent.action.CLOSE_SYSTEM_DIALOGS broadcast from \ com.package.name requires android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, \ dropping broadcast.
5.8 屏蔽不信赖的触摸事件
屏幕利用是用户与利用交互的次要形式,为了进步触摸交互的直观和安全性,Android 12 零碎会屏蔽从不同利用的窗口传递的事件。因而,这次的改变次要影响 申明抉择让触摸事件穿透窗口的利用,例如申明了 TYPE_APPLICATION_OVERLAY 和 FLAG_NOT_TOUCHABLE 的悬浮窗口。
详细分析见相干材料:行为变更 | Android 12 中不受信赖的触摸事件 —— 官网博客文章
6. 性能和电池(所有利用)
6.1 利用待机分区改良
App Standby Buckets 利用待机分区是 Android 9 引入的电池治理性能,零碎会对利用的应用早先度和应用频率对利用进行排序,别离搁置在不同的分区中。更沉闷的利用会被调配到更高优先级的分区中,而低优先级的分区中利用的作业、闹钟或 FCM 会有肯定限度。Android 12 零碎引入了一个新的分区 ——“受限”待机分区:
- 沉闷:目前正在应用,或者最近刚刚应用;
- 工作集:定期应用;
- 罕用:常常应用,但不会每天应用;
- 极少应用:不常常应用;
- 受限:利用耗费大量资源,或体现出不良行为
- 从未应用:已装置但从未运行过。
旧版本的待机分区只是依据利用的活跃度排序,而当初还有引入资源占用率的维度。能够看出,这次改变是 Google 心愿进步对耗费大量系统资源的利用的限度。
提醒:这些限度仅实用于设施应用电池供电的状况;在设施充电期间,零碎不会对利用施加这些限度。
相干材料:利用待机分区 —— 官网文档
7. 总结
关注我,带你理解更多,咱们下次见。
以下变更绝对冷门,实用价值较低,暂且按住不表:
- 行为变更 – Target 12 – 用户体验 – 大屏设施上的相机预览改良 & 富感反馈体验 & AppSearch & 游戏模式 & 近期网址共享(仅限 Pixel)
- 行为变更:Target 12 – WebView 中的古代 SameSite Cookie & 备份和复原 & 连接性 & 供应商 & 更新后的非 SDK 接口限度
- 行为变更:所有利用 – 平安和隐衷设置 – 权限软件包可见性 & 移除了 BouncyCastle 实现
- 行为变更:所有利用 – 平安和隐衷设置 –
- 行为变更:所有利用 – 媒体 & 相机 & 图形和图片 & 连接性 & 更新后的非 SDK 接口限度
参考资料
- 新版本零碎适配: Android 12 中的兼容性变更 —— 官网文档
- Android 12 正式公布 | 开发者们的全新舞台 —— 官网文档
- 行为变更:所有利用 —— 官网文档
- 行为变更:以 Android 12 为指标平台的利用 —— 官网文档
- 性能和 API 概览 —— 官网文档
你的点赞对我意义重大!微信搜寻公众号 [彭旭锐],心愿大家能够一起探讨技术,找到气味相投的敌人,咱们下次见!