目录
6.2.1 telephony API、WLAN API 和 Bluetooth API 需要精确位置权限
1 概述
Android Q 能够让用户更清楚地了解并更好地控制数据和应用功能。对于开发者而言,这些功能可能会影响您的应用可能会依赖的特定行为或数据。所有开发者都应查看隐私功能并测试他们的应用。具体影响可能会因每个应用的核心功能、定位和其他因素而异。
2 应用作用域和媒体作用域存储空间
从 Android Q 测试版 1 开始,此变更具有以下属性:
- 如果您访问和共享外部存储设备中的文件,则会影响您的应用
- 使用隔离的沙盒或媒体集合目录进行缓解
- 通过运行多个 ADB 命令启用行为
为了让用户更好地控制自己的文件,并限制文件混乱情况,Android Q 更改了应用访问设备外部存储空间中文件的方式。Android Q 用更精细的媒体特定权限替换了 READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE
权限,并且无需特定权限,应用即可访问自己在外部存储设备上的文件。这些变更会影响您的应用在外部存储设备中保存和访问文件的方式。
本指南介绍了如何更新应用,以使其可以继续共享、访问和更新保存在外部存储设备上的文件,还提供了兼容性注意事项,并说明了如何激活此行为变更。
2.1 针对应用私有文件的隔离存储沙盒
Android Q 在外部存储设备中为每个应用提供了一个“隔离存储沙盒”(例如 /sdcard
)。任何其他应用都无法直接访问您应用的沙盒文件。由于文件是您应用的私有文件,因此您不再需要任何权限即可在外部存储设备中访问和保存自己的文件。此变更可让您更轻松地保证用户文件的隐私性,并有助于减少应用所需的权限数量。
注意:如果用户卸载了您的应用,系统就会清理隔离存储沙盒中的文件。
在外部存储设备中存储文件的最佳位置是 Context.getExternalFilesDir()
返回的位置,因为此位置的行为方式在所有 Android 版本中都保持一致。使用此方法时,请在媒体环境中传递与您要创建或打开的文件类型对应的文件。例如,要访问或保存应用私有图片,请调用 Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
。
2.2 媒体文件的共享集合
如果您的应用创建了属于相应用户的文件,并且希望在卸载该应用时保留此用户,则将这些文件保存到某个通用媒体集合(也称为“共享集合”)中。共享集合包括:照片和视频、音乐和下载内容。
2.2.1 查看其他应用的文件所需的权限
您的应用无需请求任何权限即可在这些共享集合中创建和修改自己的文件。但是,如果您的应用需要创建和修改其他应用已创建的文件,则必须先请求相应的权限:
-
访问照片和视频共享集合中其他应用的文件时,需要
READ_MEDIA_IMAGES
或READ_MEDIA_VIDEO
权限(具体取决于您的应用需要访问的文件类型)。 -
访问音乐共享集合中其他应用的文件时,需要
READ_MEDIA_AUDIO
权限。
注意:未设置用于访问下载内容共享集合的权限。您的应用可以访问此集合中自己的文件。但是,要访问此集合中其他应用的文件,您必须允许用户使用系统的文件选择器应用来选择文件。
注意:如果您的应用使用存储访问框架,则无需请求这些媒体作用域权限。
详细了解如何使用其他应用的文件。
2.2.2 访问共享集合
在请求必要的权限后,您的应用会使用 MediaStore
API 访问这些集合:
- 对于照片和视频共享集合,请使用
MediaStore.Images
或MediaStore.Video
。 - 对于音乐共享集合,请使用
MediaStore.Audio
。 - 对于下载内容共享集合,请使用
MediaStore.Downloads
。
注意:对于 Android Q 上新安装的应用,对 getExternalStoragePublicDirectory()
的调用仅会提供对应用存储在其隔离存储沙盒中的文件的访问权限。要始终拥有对其他应用的文件的访问权限,请更新应用的逻辑以改用 MediaStore
。
2.2.3 保留您的应用在共享集合中的文件
默认情况下,当用户卸载您的应用时,Android Q 会清理您保存到沙盒中的文件。要在卸载应用时保留这些文件,请使用存储访问框架,或将文件保存到共享集合中。
要保留共享集合中的文件,请在相关的 MediaStore
集合中新插入一行,并用以下方法填充此行对应的列:
- 至少应为
DISPLAY_NAME
和MIME_TYPE
列提供值。 - (可选)您可以使用
PRIMARY_DIRECTORY
和SECONDARY_DIRECTORY
列来影响文件在磁盘上的存储位置。 - 保留
DATA
列不定义。这样一来,平台便可以灵活地将文件保留在沙盒之外。
插入此行后,您可以使用 ContentResolver.openFileDescriptor()
之类的 API 读取新建文件的数据或向其中写入数据。
但是,如果用户稍后重新安装了您的应用,该应用将无法访问这些文件,除非它执行以下操作之一:
- 请求对集合的相应权限。
- 从存储访问框架向用户发送请求。
这种情况类似于一个应用尝试访问另一个应用的文件的情况。
2.3 照片的特别注意事项
Android Q 新增了多项增强功能,让用户可以更好地控制在外部存储设备中访问照片的方式。
2.3.1 访问照片中的位置信息
一些照片在其 Exif 元数据中包含位置信息,以便用户查看照片的拍摄地点。由于此位置信息很敏感,因此默认情况下 Android Q 会对该信息进行遮盖。这种对位置信息的限制与适用于相机特性的限制不同。
注意:如果您的应用是用户的默认照片管理器应用,则平台会自动让您的应用访问照片中的位置信息。
如果您的应用需要访问照片的位置信息,请完成以下步骤:
- 将新的
ACCESS_MEDIA_LOCATION
权限添加到您应用的清单中。 - 在 MediaStore 对象中,调用
setRequireOriginal()
并传入照片的 URI。
2.3.2 向用户显示照片库
如果您的应用是相机应用,则它无法直接访问保存在照片和视频共享集合中的照片(除非它是设备的默认照片管理器应用)。要引导用户找到图库应用,请使用 ACTION_REVIEW
intent。
2.4 使用其他应用的文件
本节介绍了您的应用如何与其他应用存储在共享集合中的文件进行互动。
2.4.1 访问其他应用创建的文件
要访问并读取其他应用已保存到外部存储设备中的媒体文件,请完成以下步骤:
- 根据包含您要访问的文件的共享集合请求必要的权限。
- 使用
ContentResolver
对象查找并打开该文件。
注意:ContentResolver
类包含一个新方法 loadThumbnail()
,它可为您的应用提供文件预览。最好先调用 loadThumbnail()
,以便用户可以查看媒体文件的快照,无需让您的应用自己加载所有文件。此方法还支持更灵活的请求,例如请求特定尺寸以及取消请求的功能。
2.4.2 向其他应用创建的文件写入数据
通过将文件保存到共享集合,您的应用会成为该文件的所有者。通常,只有当您是共享集合中某个文件的所有者时,您的应用才能向该文件写入数据。但是,如果为您的应用分配了正确的角色,您还可以向其他应用拥有的文件写入数据:
- 如果您的应用是用户的默认照片管理器应用,则可以修改其他应用保存到照片和视频共享集合中的图片文件。
- 如果您的应用是用户的默认音乐应用,则可以修改其他应用保存到音乐共享集合中的音频文件。
注意:无论您的应用是默认的照片管理器应用还是默认的音乐应用,它都应保持正常运行。
要修改其他应用最初保存到外部存储设备中的媒体文件,请完成下列步骤之一:
- 按照角色指南中的步骤查看您的应用是默认的照片管理器应用还是默认的音乐应用。
- 使用
ContentResolver
对象找到相应文件并直接进行修改。执行编辑/修改操作时,捕获RecoverableSecurityException
以便您可以请求用户授予您对该特定内容的写入权限。
2.5 访问特定文件
在某些用例中,您的应用可能需要打开或创建它无权访问的文件:
- 在照片编辑应用中,打开一张绘图。
- 在企业办公应用中,将文本文档保存到用户选择的位置。
对于这些情况,请使用存储访问框架(该框架允许用户选择要打开的特定文件,或选择特定位置来保存文件)。
2.6 配套应用文件共享
如果您要管理一套需要相互访问彼此文件的应用,请使用 content://
URI(我们已将其作为安全最佳做法推荐)。
如需了解详情,请参阅有关如何设置文件共享的文档。
2.7 升级设备上之前安装过的应用的兼容性模式
对访问外部存储设备中文件的限制仅适用于以 Android Q 为目标平台的应用,或者在运行 Android Q 的设备上新安装的应用。
当满足以下每个条件时,系统会将您应用的文件访问权限置于兼容性模式:
- 您的应用以 Android 9(API 级别 28)或更低版本为目标平台。
- 您的应用安装在从 Android 9 升级到 Android Q 的设备上。
当您的应用处于兼容性模式时,以下文件访问行为适用:
- 您的应用可以访问在
MediaStore
集合中存储的所有文件(甚至是您的应用尚未创建的文件)。 - 面向用户的存储权限可允许或禁止您的应用访问整个外部存储设备,而不是控制对单个共享集合(如照片和视频或音乐)的访问。
在首次卸载您的应用之前,此兼容性模式一直有效。
注意:如果稍后在同一设备上重新安装您的应用,则不会重新激活兼容性模式。
2.8 标识特定的外部存储设备
在 Android 9(API 级别 28)及更低版本中,所有存储设备上的所有文件都显示在单个 "external"
卷名称下。Android Q 为每个外部存储设备提供唯一的卷名称。此命名系统可帮助您高效地整理内容并将内容编入索引,还可让您控制新内容的存储位置。
注意:主外部存储设备始终使用卷名称 "external"
。
要唯一标识外部存储设备中的特定文件,您必须同时使用卷名称和 ID。例如,主存储设备上的文件是 content://media/external/images/media/12
,而名为 FA23-3E92
的辅助存储设备上的对应文件是 content://media/FA23-3E92/images/media/12
。
您可以通过将此卷名称传递到特定媒体集合(例如 MediaStore.Images.getContentUri()
)中来访问存储在特定卷中的文件。
2.8.1 获取外部存储设备列表
要获取所有当前可用卷的名称列表,请调用 MediaStore.getAllVolumeNames()
,如以下代码段所示:
Set<String> volumeNames = MediaStore.getAllVolumeNames(context);
2.8.2 设置虚拟外部存储设备
在没有可移动外部存储设备的设备上,使用以下命令启用虚拟磁盘以进行测试:
adb shell sm set-virtual-disk true
2.9 测试行为变更
为了让您的应用与此新行为变更兼容,平台提供了多种方法来调整与此变更相关联的多个参数。
2.9.1 切换行为变更
要在 Android Q 测试版 1 中启用此行为变更,请在终端窗口中执行以下命令:
adb shell sm set-isolated-storage on
运行此命令后,设备将重启。如果设备未重启,请稍等片刻,然后再尝试重新运行此命令。
要确认行为变更是否已生效,请使用以下命令:
adb shell getprop sys.isolated_storage_snapshot
2.9.2 测试兼容性模式行为
测试您的应用时,您可以通过在终端窗口中运行以下命令来为外部文件存储访问权限启用兼容性模式:
adb shell cmd appops set your-package-name android:legacy_storage allow
要停用兼容性模式,请在 Android Q 上卸载然后重新安装您的应用,或在终端窗口中运行以下命令:
adb shell cmd appops set your-package-name android:legacy_storage default
2.10 以文件管理器的形式浏览外部存储设备
要以文件管理器的形式广泛访问外部存储设备中的目录,请使用 ACTION_OPEN_DOCUMENT_TREE
intent。有关示例,请参阅 GitHub 上的 android-DirectorySelection 示例。
注意:在 Android Q 中,StorageVolume
类中的 createAccessIntent()
方法已被弃用,因此您不应使用此方法浏览外部存储设备。如果您使用此方法浏览外部存储设备,运行 Android Q 设备的用户将无法在您的应用中查看保存在外部存储设备中的文件。
3 用户可控制应用对设备位置信息的访问权限
从 Android Q 测试版 1 开始,此项变更具有以下特性:
- 如果您在后台时请求访问用户的位置信息,则会影响您的应用
- 缓解方式包括:使用新权限在后台访问位置信息,并在没有后台位置信息更新的情况下确保优雅降级
- 这种行为在 Android Q 上始终处于启用状态
图 1. 请求用户同意让应用访问位置信息的对话框
Android Q 可让用户更好地控制应用何时能够访问设备位置信息。当在 Android Q 上运行的应用请求位置信息访问权限时,用户会看到如图 1 所示的对话框。此对话框可让用户将位置信息访问权限授予到两个不同的范围:在使用中(仅限前台)或始终(前台和后台)。
为了让用户更好地控制应用对位置信息的访问权限,Android Q 引入了新的位置权限 ACCESS_BACKGROUND_LOCATION
。与现有的 ACCESS_FINE_LOCATION
和 ACCESS_COARSE_LOCATION
权限不同,新权限仅会影响应用在后台运行时对位置信息的访问权。除非应用的某个 Activity 可见或应用正在运行前台服务,否则应用将被视为在后台运行。
3.1 在后台请求访问位置信息
如果您的应用以 Android Q 为目标平台,并且在后台运行时需要访问用户的位置信息,则您必须在应用的清单文件中声明新权限:
<manifest> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </manifest>
如果您的应用在 Android Q 上运行但目标平台是 Android 9(API 级别 28)或更低版本,则以下行为适用:
- 如果您的应用为
ACCESS_FINE_LOCATION
或ACCESS_COARSE_LOCATION
声明了<uses-permission>
标签,则系统会在安装期间自动为ACCESS_BACKGROUND_LOCATION
添加<uses-permission>
标签。 - 如果您的应用请求了
ACCESS_FINE_LOCATION
或ACCESS_COARSE_LOCATION
,系统会自动将ACCESS_BACKGROUND_LOCATION
添加到请求中。
注意:虽然您的应用可以请求并获得 ACCESS_BACKGROUND_LOCATION
权限,但用户可以通过选择让该应用只能在前台访问位置信息来撤消此权限。
3.2 请求后台位置信息访问权限
注意:此部分适用于在 Android Q 上运行的所有应用,无论它们的目标平台是哪个版本。
如果应用的用例需要在后台运行时访问位置信息,请务必考虑您需要此权限的范围:
- 应用的用例依赖于延续用户发起的操作,例如导航或智能家居操作。在这种情况下,请配置前台服务,以便在用户按下设备上的主屏幕按钮或关闭设备显示屏后,该服务可保留对用户位置信息的访问权限,即使用户已要求您的应用只能在前台访问其位置信息,也是如此。
- 应用的用例始终依赖于定期查看用户的位置信息,例如地理围栏或位置信息分享。在这种情况下,应用应向用户说明他们需要允许该应用始终都能访问他们的位置信息,以确保正常运行,然后请求在后台访问位置信息。
3.2.1 延续用户发起的操作
注意:如果您的应用在后台运行时不需要访问位置信息,则最佳做法是以 Android Q 为目标平台,并且不请求新的后台位置权限。这样一来,应用仅在使用中时收到位置信息更新。
如果用户只允许您的应用在前台访问位置信息,那么即使用户按下设备上的主屏幕按钮或关闭设备的显示屏,用户可能仍会启动要求该应用访问其位置信息的工作流。
要在此特定用例中保留对用户位置信息的访问权,请启动您已在应用清单中声明具有前台服务类型 "location"
的前台服务:
<service android:name="MyNavigationService" android:foregroundServiceType="location" ... > ... </service>
在启动前台服务之前,请确保您的应用仍可访问用户的位置信息:
boolean permissionAccessCoarseLocationApproved = ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (permissionAccessCoarseLocationApproved) { // App has permission to access location in the foreground. Start your // foreground service that has a foreground service type of "location". } else { // Make a request for foreground-only location access. ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION}, your-permission-request-code); }
3.2.2 定期查看用户的位置信息
您的应用可能有一个需要始终都能访问用户位置信息的用例。此类用例包括地理围栏以及与亲朋好友分享位置信息。
如果这些条件适用于您的应用,只要用户授予该应用对其位置信息的始终访问权,您就可以继续请求位置信息更新而无需任何更改:
<!-- It's unnecessary to include a foreground service type for services that must have access to the user's location "all the time" in order to run successfully.--> <service android:name="MyFamilyLocationSharingService" ... > ... </service>
虽然您的应用可以请求在后台访问位置信息,但用户也可以选择使应用只能在前台访问位置信息,或者完全撤消访问权。因此,每当您的应用启动服务时,都要查看用户是否仍允许该应用在后台访问位置信息。
如果用户已要求您的应用只能在前台访问位置信息,则最佳做法是让该应用显示一个自定义对话框,提醒用户如果该应用不能始终访问其位置信息便无法正常运行。用户确认此对话框后,您可以请求后台位置信息访问权,此时会出现如图 2 所示的系统对话框:
图 2. 请求用户同意让应用始终访问位置信息的对话框
以下代码段中显示了此权限检查逻辑的示例:
boolean permissionAccessCoarseLocationApproved = ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (permissionAccessCoarseLocationApproved) { boolean backgroundLocationPermissionApproved = ActivityCompat.checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED; if (backgroundLocationPermissionApproved) { // App can access location both in the foreground and in the background. // Start your service that doesn't have a foreground service type // defined. } else { // App can only access location in the foreground. Display a dialog // warning the user that your app must have all-the-time access to // location in order to function properly. Then, request background // location. ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_BACKGROUND_LOCATION}, your-permission-request-code); } } else { // App doesn't have access to the user's location at all. Make full request // for permission. ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION }, your-permission-request-code); }
3.3 遵循位置信息最佳做法
通过按照本指南中显示的方法来检查和请求位置权限,您的应用可以成功跟踪其有关用户位置信息的访问权限等级。
要详细了解如何确保用户数据安全,请参阅权限最佳做法指南。
3.3.1 仅请求您所需的权限
仅在需要时请求权限。例如:
- 请勿在应用启动时请求位置权限(除非绝对有必要)。
- 如果您的应用以 Android Q 为目标平台,并且仅在前台运行时需要访问位置信息,请不要请求
ACCESS_BACKGROUND_LOCATION
。
3.3.2 在未授予权限时支持优雅降级
为了保持良好的用户体验,请在设计应用时确保它可以优雅地处理以下情况:
- 应用无法访问位置信息。
- 应用在后台运行时无法访问位置信息。
4 针对后台 Activity 启动的限制
从 Android Q 测试版 1 开始,此项变更具有以下特性:
- 如果您在未与用户互动的情况下启动 Activity,则会影响您的应用
- 使用由通知触发的 Activity 进行缓解
- 通过关闭允许系统执行后台活动开发者选项来启用限制
Android Q 对应用可启动 Activity 的时间施加了限制。此项行为变更有助于最大限度地减少对用户造成的中断,并且可以让用户更好地控制其屏幕上显示的内容。具体而言,在 Android Q 上运行的应用只有在满足以下一个或多个条件时才能启动 Activity:
- 该应用具有可见窗口,例如在前台运行的 Activity。
- 在前台运行的另一个应用会发送属于该应用的
PendingIntent
。示例包括发送菜单项待定 intent 的自定义标签页提供程序。 - 系统发送属于该应用的
PendingIntent
,例如点按通知。只有应用应启动界面的待定 intent 才可以免除。 - 系统向应用发送广播,例如
SECRET_CODE_ACTION
。只有应用应启动界面的特定广播才可以免除。
注意:出于 Activity 启动的目的,前台服务不会将应用限定为在前台运行。
此项行为变更适用于在 Android Q 上运行的所有应用,包括以 Android 9(API 级别 28)或更低版本为目标平台的应用。此外,即使您的应用以 Android 9 或更低版本为目标平台并且最初安装在运行 Android 9 或更低版本的设备上,该行为变更仍会在设备升级到 Android Q 后生效。
但是,只要您的应用启动 Activity 是因用户互动直接引发的,该应用就极有可能不会受到此项变更的影响。实际上,大多数应用都不会受到此项变更的影响。如果您发现自己的应用受到了影响,请向我们发送反馈。
4.1 警告消息
在测试版 1 中,如果您的应用在 Android Q 上运行并尝试从后台启动 Activity,则平台允许该 Activity 启动,但它会向 logcat 发送警告消息并显示以下警告提示消息:
This background activity start from package-name will be blocked in future Q builds.
与 Android Q 中在后台启动 Activity 相关的限制与系统在设备进入固定屏幕状态后阻止 Activity 启动的方式类似。
4.2 针对有时效性的事件创建通知
几乎在所有情况下,后台应用都应创建通知以便向用户提供信息,而不是直接启动 Activity。
在特定情况下,您的应用可能需要立即引起用户的注意,例如闹钟正在响铃或有来电时。您可能已出于此目的将应用配置为启动后台 Activity。要在运行 Android Q 的设备上提供相同的行为,请完成以下各部分中所示的步骤。
4.2.1 创建高优先级通知
创建通知时,请务必添加描述性标题和消息,并视需要选择提供全屏 intent。
以下代码段中显示了示例通知:
val fullScreenIntent = Intent(this, CallActivity::class.java) val fullScreenPendingIntent = PendingIntent.getActivity(this, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT) val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("Incoming call") .setContentText("(919) 555-1234") .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_CALL) // Use a full-screen intent only for the highest-priority alerts where you // have an associated activity that you would like to launch after the user // interacts with the notification. Also, if your app targets Android Q, you // need to request the USE_FULL_SCREEN_INTENT permission in order for the // platform to invoke this notification. .setFullScreenIntent(fullScreenPendingIntent, true) val incomingCallNotification = notificationBuilder.build()
4.2.2 向用户显示通知
向用户显示通知时,他们可以根据当前上下文选择是确认还是关闭应用的提醒。例如,用户可以选择是接受还是拒绝来电。
如果您的通知正在进行(例如来电),请将该通知与前台服务相关联。以下代码段展示了如何显示与前台服务关联的通知:
// Provide a unique integer for the "notificationId" of each notification. startForeground(notificationId, notification)
注意:系统界面可以选择在用户使用设备时显示提醒式通知,而不是启动全屏 intent。
4.3 通知的优势
这种基于通知的提醒系统可以为用户提供以下几个优势:
- 当用户使用设备时,系统会向他们显示提醒式通知,从而让他们接听或拒绝来电或者关闭闹钟。用户可以维护其当前的上下文并控制他们在屏幕上看到的内容。
- 您的来电或闹钟会受到用户的“勿扰”规则的影响。例如,在启用“勿扰”功能后,用户可以仅允许来自特定联系人或重复来电者的来电。
- 当设备的屏幕关闭时,您的全屏 intent 会立即启动。
- 在设备的设置屏幕中,用户可以查看哪些应用最近发送了通知(包括来自特定通知渠道的通知)。在该屏幕中,用户可以控制他们的通知偏好设置。
4.4 启用行为变更
即使此项行为变更默认不会在 Android Q 测试版 1 中生效,您也可以通过完成以下任务之一来模拟此项行为变更:
- 依次转到设置 > 开发者选项,然后停用允许系统执行后台活动选项。
-
在终端窗口中,运行以下命令:
adb shell settings put global background_activity_starts_enabled 0
通过测试行为变更,您可以更加确信用户可以在其设备上安装 Android Q 后继续按预期与您的应用互动。
5 数据和标识符变更
该小节介绍了对访问数据和系统标识符施加的几项限制。这些变更有助于保护用户的隐私。
其中一些变更会影响在 Android Q 上运行的所有应用,而其他变更仅会影响以 Android Q 为目标平台的应用。
5.1 影响所有应用的变更
以下变更会影响在 Android Q 上运行的所有应用,即使这些应用以 Android 9(API 级别 28)或更低版本为目标平台也是如此。
5.1.1 联系人亲密程度
从 Android Q 开始,平台不再跟踪联系人亲密程度信息。因此,如果您的应用对用户的联系人进行搜索,则系统将不再按互动频率对搜索结果排序。
联系人提供程序指南包含一项描述特定字段和方法的声明(从 Android Q 开始,这些字段和方法在所有设备上已作废)。
5.1.2 随机选择的 MAC 地址
默认情况下,搭载 Android Q 的设备会传输随机选择的 MAC 地址。如果您的应用处理企业用例,平台会提供几个新的 API:
- 获取随机选择的 MAC 地址:设备所有者应用和个人资料所有者应用可以通过调用
WifiConfiguration.getRandomizedMacAddress()
检索分配给特定网络的随机选择 MAC 地址。 - 获取实际的出厂 MAC 地址:设备所有者应用可以通过调用
WifiInfo.getFactoryMacAddress()
检索设备的实际硬件 MAC 地址。此方法对于跟踪设备队列非常有用。
5.1.3 访问 /proc/net 文件系统
Android Q 撤消了 /proc/net
访问权限,其中包含有关设备网络状态的信息。需要访问此信息的应用(如 VPN)应引用 NetworkStatsManager
和 ConnectivityManager
类。
5.1.4 不可重置的设备标识符
从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE
签名权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。许多用例不需要不可重置的设备标识符。如果您的应用没有该权限,但您仍尝试查询标识符的相关信息,则平台的响应会因目标 SDK 版本而异:
- 如果应用以 Android Q 为目标平台,则会发生
SecurityException
。 - 如果应用以 Android 9(API 级别 28)或更低版本为目标平台,则相应方法会返回
null
或占位符数据(如果应用具有READ_PHONE_STATE
权限)。否则,会发生SecurityException
。
注意:如果您的应用是设备或个人资料所有者应用,则您只需要 READ_PHONE_STATE
权限即可访问不可重置的设备标识符(即使该应用以 Android Q 为目标平台,也是如此)。此外,如果您的应用具有特殊运营商权限,则您不需要任何权限即可访问这些标识符。
如果您的应用将不可重置的设备标识符用于广告跟踪或用户分析目的,请为这些特定用例创建 Android 广告 ID。要了解详情,请参阅唯一标识符的最佳做法。
5.1.5 访问剪贴板数据
除非您的应用是默认输入法 (IME) 或是目前处于焦点的应用,否则应用无法访问剪贴板数据。
5.2 影响以 Android Q 为目标平台的应用的变更
以下变更仅会影响以 Android Q 为目标平台的应用。
5.2.1 访问 USB 串行设备需要用户授予权限
如果您的应用以 Android Q 为目标平台,则该应用只能在用户授予其访问 USB 设备或配件的权限后才能读取序列号。
6 位置和网络权限变更
本小节介绍了对访问位置和网络信息施加的几项限制。这些变更有助于保护用户的隐私。
其中一些变更会影响在 Android Q 上运行的所有应用,而其他变更仅会影响以 Android Q 为目标平台的应用。
6.1 影响所有应用的变更
以下变更会影响在 Android Q 上运行的所有应用,即使这些应用以 Android 9(API 级别 28)或更低版本作为目标平台也是如此。
6.1.1 访问所有相机信息都需要获得权限
Android Q 更改了 getCameraCharacteristics()
方法默认返回的信息的广度。具体而言就是,您的应用必须具有 CAMERA
权限才能访问此方法的返回值中可能包含的设备特定元数据。
如果您的应用没有 CAMERA
权限,它将无法访问以下字段:
ANDROID_LENS_POSE_ROTATION
ANDROID_LENS_POSE_TRANSLATION
ANDROID_LENS_INTRINSIC_CALIBRATION
ANDROID_LENS_RADIAL_DISTORTION
ANDROID_LENS_POSE_REFERENCE
ANDROID_LENS_DISTORTION
ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE
ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE
ANDROID_SENSOR_REFERENCE_ILLUMINANT1
ANDROID_SENSOR_REFERENCE_ILLUMINANT2
ANDROID_SENSOR_CALIBRATION_TRANSFORM1
ANDROID_SENSOR_CALIBRATION_TRANSFORM2
ANDROID_SENSOR_COLOR_TRANSFORM1
ANDROID_SENSOR_COLOR_TRANSFORM2
ANDROID_SENSOR_FORWARD_MATRIX1
ANDROID_SENSOR_FORWARD_MATRIX2
6.1.2 对启用和停用 WLAN 的限制
在 Android Q 上运行的应用无法启用或停用 WLAN。WifiManager.setWifiEnabled()
方法始终返回 false
。
如果需要,请使用设置面板提示用户启用和停用 WLAN。
6.2 影响以 Android Q 为目标平台的应用的变更
以下变更仅会影响以 Android Q 为目标平台的应用。
6.2.1 telephony API、WLAN API 和 Bluetooth API 需要精确位置权限
除非您的应用具有 ACCESS_FINE_LOCATION
权限,否则在 Android Q 上运行时,这些应用无法使用 WLAN API、WLAN Aware API 或 Bluetooth API 中的多种方法。要查看受影响方法的列表,请参阅隐私附录。
注意:如果您的应用在 Android Q 上运行但以 Android 9(API 级别 28)或更低版本为目标平台,则只要您的应用具有 ACCESS_COARSE_LOCATION
或 ACCESS_FINE_LOCATION
权限,您就可以使用受影响的 API。
6.2.2 WLAN 网络配置限制
为了保护用户隐私,现在只能对手动配置系统的 WLAN 网络列表。如果您的应用以 Android Q 为目标平台,则下列方法将不再返回有用数据:
getConfiguredNetworks()
方法始终返回空列表。- 每个返回整数值的网络操作方法(
addNetwork()
和updateNetwork()
)始终返回 -1。 - 每个返回布尔值的网络操作(
removeNetwork()
、reassociate()
、enableNetwork()
、disableNetwork()
、reconnect()
和disconnect()
)始终返回false
。
如果您的应用需要连接到 WLAN 网络,请使用以下备用方法:
- 要触发与 WLAN 网络的即时本地连接,请在标准
NetworkRequest
对象中使用WifiNetworkSpecifier
。 - 要添加 WLAN 网络以便考虑为用户提供互联网访问权限,请使用 WifiNetworkSuggestion 对象。您可以通过分别调用
WifiManager.addNetworkSuggestions()
和WifiManager.removeNetworkSuggestions()
添加和移除显示在自动连接网络选择对话框中的网络。这些方法不需要任何位置权限。