本文将重点介绍该版本特性中部分需要开发适配的部分,以官方文档说明为基础,汇总自己在适配中踩过的坑以及经验,后续遇到相关问题会持续更新。
API = 30,主要影响分类:
影响所有应用的行为变更(不管targetSdk是多少,对所有跑在R设备上的应用均有影响)影响以 Android R为目标平台的应用的行为变更(targetSDK ==R ,且跑在R设备上的应用才有影响)
影响所有应用的行为变更
官方文档在这里。
隐私设置,其中包括:
单次授权:让用户可以选择授予更多对位置信息、麦克风和摄像头的临时访问权限。 权限对话框的可见性:一再拒绝某项权限表示用户希望“不再询问”。这个只是官方的一个建议。数据访问审核:深入了解您的应用在何处访问私密数据。可以注册AppOpsManager.OnOpNotedCallback
实例,该实例可在每次发生以下任意事件时执行相应操作。应用的代码访问私密数据。为了帮助您确定应用的哪个逻辑部分调用了事件,您可以按归因标记审核数据访问。依赖库或 SDK 中的代码访问私密数据。(这个没实践过)系统提醒窗口权限:根据请求自动向某些类型的应用授予SYSTEM_ALERT_WINDOW
权限。此外,包含ACTION_MANAGE_OVERLAY_PERMISSION
intent 操作的 intent 始终会将用户转至系统设置中的屏幕。永久SIM卡标识符:在 Android 11 及更高版本中,使用getIccId()
方法访问不可重置的 ICCID 受到限制。该方法会返回一个非 null 的空字符串。如需唯一标识设备上安装的 SIM 卡,请改用getSubscriptionId()
方法。订阅 ID 会提供一个索引值(从 1 开始),用于唯一识别已安装的 SIM 卡(包括实体 SIM 卡和电子 SIM 卡)。除非设备恢复出厂设置,否则此标识符的值对于给定 SIM 卡是保持不变的。
安全性,其中包括:
SSL 套接字默认情况下使用 Conscrypt SSL 引擎:Android 的默认SSLSocket
实现基于Conscrypt 。从 Android 11 开始,该实现是在 Conscrypt 的SSLEngine
之上内部构建的。
Scudo Hardened Allocator:Android 11 在内部使用 Scudo Hardened Allocator 为堆分配提供服务。Scudo 能够检测并减轻某些类型的内存安全违规行为。如果您在原生代码崩溃报告中发现与 Scudo 相关的崩溃(例如 Scudo ERROR:),请参阅 Scudo 问题排查文档。
针对 5G 的模拟器支持Scudo 是一个动态的用户模式内存分配器(也称为堆分配器),旨在抵御与堆相关的漏洞(如基于堆的缓冲区溢出、释放后再使用和重复释放),
同时保持性能良好。它提供了标准 C 分配和取消分配基元(如 malloc 和 free),以及 C++ 基元(如 new 和 delete)
Android 11 添加了5G API,使您的应用能够添加各种先进的功能。如需在添加这些功能时对其进行测试,您可以使用Android SDK 模拟器的新功能。这项新功能是在模拟器版本 30.0.22 中添加的。
选择 5G 网络设置可将TelephonyDisplayInfo设为OVERRIDE_NETWORK_TYPE_NR_NSA,修改带宽估算值,还允许您设置按流量计费性,
以验证您的应用是否会对NET_CAPABILITY_TEMPORARILY_NOT_METERED状态的变化做出适当的响应。
性能和调试
JobScheduler API 调用限制调试
JobScheduler任务调度器,可以在设备空闲时做一些任务处理。开发者可以利用此服务发现潜在的性能问题。对于debuggable
清单属性设置为 true 的应用,超出速率限制的JobScheduler
API 调用将返回RESULT_FAILURE。如此设置限制,正当合理的用例应该就不会受到影响。
文件描述符排错程序:Android 10 引入了JobScheduler是由SystemServer进程启动的一个系统服务
fdsan
(文件描述符排错程序)。fdsan
检测错误处理文件描述符所有权的错误,例如 use-after-close 和 double-close。在 Android 11 中,fdsan
的默认模式发生了变化。现在,fdsan
会在检测到错误时中止,而以前的行为则是记录警告并继续。如果您在应用中发现由于fdsan
而导致的崩溃,请参阅fdsan documentation
。文件描述符(FileDescriptor) 是Unix/Linux系统文件操作的相关概念,它在形式上是一个非负整数。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。
系统的进程也就是使用了这个fd来标示打开的文件,有了它就能对文件做各种操作,获得文件的各种相关信息了。
非SDK接口限制:Android 11 包含更新后的受限制非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。跟其他版本一样,Android11也会限制一些接口,包括灰名单和白名单,具体看对非 SDK 接口的限制。
与其他应用交互
分享内容 URI:应用与其他应用分享内容 URI,相应 intent 必须至少设置以下 intent 标记中的一个,以便授予对 URI 的访问权限:FLAG_GRANT_READ_URI_PERMISSION
和FLAG_GRANT_WRITE_URI_PERMISSION
。这样一来,如果其他应用以 Android 11 为目标平台,相应应用仍可访问内容 URI。即使内容 URI 与不属于你的应用的内容提供程序相关联,应用也必须包含 intent 标记。
以 Android 11 为目标平台的应用行为变更:
隐私设置,Android11 引入了一些变更和限制来加强用户隐私保护,其中包括:
强制执行分区存储:对外部存储目录的访问仅限于应用专用目录,以及应用已创建的特定类型的媒体。
分区存储将存储空间分为两部分:
1、公共目录:Downloads、Documents、Pictures 、DCIM、Movies、Music、Ringtones等
公共目录的文件在App卸载后,不会删除;可以通过SAF、MediaStore接口访问;拥有权限,也能通过路径直接访问
2、 应用专属目录:应用专属目录只能自己直接访问;App卸载,数据会清除。
targetSdkVersion = 29应用中,设置android:requestLegacyExternalStorage=“true”,就可以不启动分区存储,Environment.getExternalStoragePublicDirectory读取正常使用。
targetSdkVersion = 30中强制开启分区存储。
targetSdkVersion 由29修改到30,覆盖安装,增加android:preserveLegacyExternalStorage=“true”,Environment.getExternalStoragePublicDirectory读写正常不报错
targetSdkVersion 由29修改到30,卸载安装,Environment.getExternalStoragePublicDirectory读写报错,程序崩溃(open failed: EACCES (Permission denied))
数据迁移,可以将数据迁移到使用分区存储时可见的目录。先通过Environment.isExternalStorageLegacy() (added in api 29)方法判断存储模式,再操作文件;
自动重置权限:如果用户几个月未与应用互动,系统会自动重置应用的敏感权限。在后台访问位置信息的权限:用户必须转到系统设置,才能向应用授予在后台访问位置信息的权限。
在较低版本的Android系统中,当应用获得前台位置信息访问权限时,授权后,就能同时获取前台位置权限和后台位置权限(ACCESS_BACKGROUND_LOCATION)。
Android 11中必须单独申请后台位置权限,而且,要先获取前台权限,再获取后台服务权限(顺序不能换)。
如果在没获取前台权限时就执行获取后台权限的代码会没反应,等获取前台权限(ACCESS_COARSE_LOCATION/ACCESS_FINE_LOCATION)之后,申请后台权限就会跳转到一个新的权限页面,必须选择Allow all the time (始终允许)才能获得后台位置权限。
前台服务:如果应用以 Android11 或更高版本为目标平台,在 Android11 中,前台服务何时可以访问设备的位置信息、摄像头和麦克风发生了一些变化。
软件包可见性:当应用查询设备上已安装应用的列表时,系统会过滤返回的列表。原本调用 getInstalledApplications() 或 getInstalledPackages() queryIntentActivities()的地方会受到影响。如果应用在前台服务中访问摄像头或麦克风,则必须添加前台服务类型
camera
和microphone(
foregroundType = “MicroXXX|camera”)。
如果应用在后台运行时启动了某项前台服务,则该前台服务无法访问麦克风或摄像头。此外,除非您的应用具有在后台访问位置信息的权限,否则该服务无法访问位置信息。
查询特定软件包及与之交互
如果你知道要查询或与之交互的一组特定应用,要将其软件包名称添加到
<queries>
元素内的一组<package>
元素中:
<manifest package="com.example.game"><queries><package android:name="com.example.store" /><package android:name="com.example.services" /></queries>...</manifest>
在给定 intent 过滤器的情况下查询应用及与之交互
如果不知道要添加的具体软件包名称,可以在
<queries>
元素中列出intent 过滤器签名。应用就可以发现具有匹配的<intent-filter>
元素的应用。以下示例允许应用看到支持 JPEG 图片共享功能的已安装应用:
<manifest package="com.example.game"><queries><intent><action android:name="android.intent.action.SEND" /><data android:mimeType="image/jpeg" /></intent></queries>...</manifest>
在给定提供程序授权的情况下查询应用及与之交互
如果需要查询Content Provider但不知道具体的软件包名称,可以在
<provider>
元素中声明该提供程序授权,如以下所示:
<manifest package="com.example.suite.enterprise"><queries><provider android:authorities="com.example.settings.files" /></queries>...</manifest>
查询所有应用及与之交互
在极少数情况下,应用可能需要查询设备上的所有已安装应用或与之交互。系统会提供
QUERY_ALL_PACKAGES
权限。下面列出了适合添加权限的用例的一些示例:
启动器应用无障碍应用浏览器点对点 (P2P) 共享应用设备管理应用安全应用
文本消息框 API 变更
以 Android11 或更高版本为目标平台的应用会发现文本消息框受到以下负面影响:
getView()
方法返回null
。以下方法的返回值并不反映实际值,因此不应在应用中依赖于它们:
getHorizontalMargin()
getVerticalMargin()
getGravity()
getXOffset()
getYOffset()
以下方法是空操作,因此应用不应使用它们:
setMargin()
setGravity()
应用打包和安装
压缩的资源文件
现在需要 APK 签名方案 v2如果以 Android11(API 级别30)或更高版本为目标平台的应用包含压缩的
resources.arsc
文件(由aapt生成的所有apk资源(图标,字串等)的索引文件)或者如果此文件未按 4 字节边界对齐,应用将无法安装。如果存在其中任意一种情况,系统将无法对此文件进行内存映射。无法进行内存映射的资源表必须读入 RAM 中的缓冲区,从而给系统造成不必要的内存压力,并大大增加设备的 RAM 使用量。
对于以 Android11(API 级别30)为目标平台,且目前仅使用 APK 签名方案 v1 签名的应用,现在还必须使用APK 签名方案 v2或更高版本进行签名。用户无法在搭载 Android11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用。
如需应用是否已使用 APK 签名方案 v2 或更高版本进行签名,可以在命令行中使用AS或
apksigner
工具。
兼容性测试
可以在设备的开发者选项中查看当前已启用的变更,并且可以启用/停用这些变更。如需访问这些选项,请按以下步骤操作:
如果开发者选项尚未启用,先启用开发者选项。打开设备的“设置”应用,然后依次导航到系统 > 高级 > 开发者选项 > 应用兼容性变更。从列表中选择您的应用。