作者 / Fred Chung
Android 11 的最终版本已正式公布!该版本连续了之前发行版本里不断改进的隐衷策略,为用户提供更加欠缺的管制机制和透明度,并帮忙利用更好地解决本身的数据。
其中很多优化将以后安全策略的最佳实际利用于最近的 Android 发行版本中(它们并不仅仅针对 Android 11)。在本文中,咱们将以上面四个最佳实际作为切入点,助力您的利用设计与时俱进,并打算开始进行兼容性测试。
- 解决内容 URI 分享
- 递增式权限申请
- 在前台拜访敏感数据
- 应用可重置的标识符
为其它利用提供适合的 URI 权限
随着 Android 11 中 软件包可见性 的策略更新,指标 API 级别为 30 的利用对设施上已装置的其它软件包默认仅领有受限的可见性。这样的设计旨在为利用“查看”设施上的其它已装置软件包时,提供更好的“问责”制度。
为了简化迁徙,对于常见的利用场景,咱们提供了 实现指南。通常,利用须要具备对其它已装置软件包的可见性(通过 PackageManager API 验证)才能够和其它软件包进行交互。该个性通常利用于诸如:启动服务,或者拜访属于其它利用的 Content Provider。
您拜访 Content Provider 的模式可能不是通过发送显式 intent 到某个特定的利用,而是通过发送隐式 intent。这样的话,您无奈预判接收端利用(最终解决这个 intent 的利用)的指标 API 等级,而这个等级决定了接收端利用是否会受到 Android 11 中引入的利用包可见性限度的影响。
为了保障接收端利用可能 ” 查看 ” 您的软件包,从而可能拜访任何共享的 URI,您须要在 intent 中增加 FLAG_GRANT_READ_URI_PERMISSION 和 / 或者 FLAG_GRANT_WRITE_URI_PERMISSION
。请留神,写入权限并不蕴含读取拜访权限。当被 intent 触发当前,接收端利用会被授予对相干 URI 的长期拜访权限。
val shareIntent = Intent(Intent.ACTION_VIEW).apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
data = // 须要向其它利用共享的 Content Uri
}
随着利用的指标 SDK 版本的更新(即便更新到 Android 11 之前的版本),请您特地关注波及到与其它利用分享 Content Provider 拜访权限的用例,并确保授予适当的 URI 权限。无论哪个利用是这 content provider 的拥有者,这个策略都管用。
通常,咱们要将数据拜访水平限度为当前任务所需的程度,如果您遵循了这个最佳实际,您的 Content Provider 拜访权限应该是依照个别 URI 模式 设定的。只有做到这点,您的 Content Provider 就曾经能够兼容 Android 11 了!
递增式申请权限
Android 用户钻研报告 显示,在申请获取用户的受权时,那些合乎用户期望值的申请更有可能被获准。因而,当您利用中的某个性能须要这些权限时,最佳实际是在上下文中 申请权限。
用户授予权限的起因排行。起源:Android 用户钻研报告
△ 大多数用户会为了应用某个特定的性能而抉择批准受权
这项策略对于敏感权限尤其实用,如地位拜访权限。从 Android 10 开始,平台引入了细粒度的地位模型,辨别了前台和后盾地位拜访。大多数地位场景仅须要前台拜访,比方当用户在操作 Activity 的时候。
事实上,Google Play 曾经出台了相干政策限度不必要的后盾地位拜访。要查看您的利用可能在哪些地方从后盾拜访地位,请参阅:后盾拜访地位信息文档。如果您的利用须要后盾地位权限,比方天文围栏利用,请确保后盾地位对您的功能设计是不可或缺的。
对于实用的利用,须要先申请前台地位权限,而后在稍晚些再申请后盾地位权限。这种办法为用户提供了管制权限授予级别的抉择。此外,您还能够有策略地显示一个权限申请的阐明,或者设计一个正当的交互界面,为用户提供更多信息,以阐明用户授予地位权限之后所取得的的性能晋升。
Android 11 要求面向 API 级别为 30 的利用应用递增式地位权限申请。任何同时申请前台地位权限(无论是粗略地位还是准确地位)和后盾地位权限的申请都会被疏忽并且返回如下错误信息。
E/GrantPermissionsActivity: Apps targeting 30 must have foreground permission before requesting background and must request background on its own.
请留神在 requestPermissions()
API 申请的任何其它非地位权限也会同时被疏忽。
因为 requestPermissions
API 承受一个由所需权限组成的数组作为参数,您现有的代码可能已有了同时申请多个权限的状况(如下所示),因而这里咱们激励大家检查和审核一下本人的代码,如果代码批改影响到用户交互,则须要按需进行相应设计。
如果启用了 ActivityCompat
或者框架 API:
requestPermissions(
arrayOf(
// 不要同时申请前台地位权限和后盾地位权限
// 因为所有同时申请的权限都会被疏忽
// 而是通过增量式申请地位权限
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
...)
)
同样地,如果启用了 Jetpack Activity 库:
// 应用 Activity 库
val requestPermissionsLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
map: MutableMap<String, Boolean> ->
...
}
...
requestPermissionsLauncher.launch(
arrayOf(
// 不要同时申请前台地位权限和后盾地位权限
// 因为所有同时申请的权限都会被疏忽
// 而是通过增量式申请地位权限
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION,
...)
)
正当拜访地位、麦克风和相机
Android 的零碎设计反对公开通明地拜访敏感数据,比方麦克风、相机和地位。例如,利用在前台的时候,也就是用户能看到利用界面的时候,才能够应用麦克风和相机。这样能够进步公开透明性,所以用户能够在知情的状况下启用相干个性。
如果您的利用蕴含拜访敏感数据的前台服务,请确认利用场景中蕴含间接的用户交互,使用户能够管制所执行的工作。例如,在一个视频会议利用中,您能够应用一个前台服务来反对沉闷的会议过程,其中会波及到拜访麦克风和相机。其中应该蕴含一个对于用户可见的用于启动和进行会议过程的操作,也就是该前台服务。
此外,您的利用必须正确设置 foregroundServiceType
属性来表明地位、麦克风或者相机的用处。这样能够为利用减少零碎可见性,同时在 Android 11 中也是必须配置的属性。更多信息请拜访:Android 11 中的前台服务。
您可能须要在 AndroidManifest 中申明多种数据类型的用处。
android:foregroundServiceType = "microphone location camera"
如果您的性能是基于 WorkManager 的 长时间运行的 worker 来实现的,那么它实际上是运行在叫做 SystemForegroundService
的前台服务上。您应该在利用的 AndroidManifest 中蕴含适宜的前台服务类型,它会同 Jetpack 库的 AAR AndroidManifest 文件 合并。
在利用的 AndroidManifest 中增加上面的申明,并且在其中定义所需的前台服务类型。
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="location|microphone"// 这里抉择和您的利用相干的服务类型
tools:node="merge" />
当您须要将 worker 以前台服务运行时,您须要将适合的前台服务类型传入 ForegroundInfo 对象。传入的服务类型必须和下面在 AndroidManifest 中增加的申明统一或者是其子集。
setForeground(
ForegroundInfo(NOTIF_ID,
notification.build(),
// 前台服务类型
ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION or ...)
)
弃用不可重置标识符
Android 零碎应用了一些不可重置的硬件标识符,比方 IMEI 以反对各种操作系统性能。出于隐衷方面的思考,这些绝对“弱小”的持久性和唯一性的标识符不适宜用于大部分利用场景。
从 Android 10 开始,系统对不可重置的设施标识符 施行了限度。比方,只有带有 READ_PRIVILEGED_PHONE_STATE 权限的零碎利用才能够通过 getSimSerialNumber()) 办法拜访 SIM 卡的硬件标识符。在 Android 11 中,操作系统对 getIccId()) 办法也减少了相似的限度来进一步 限度拜访权限,当初该办法仅返回空字符串。
对于须要应用 SIM 卡信息作为唯一性标识的利用,须要在 Android 11 里进行“空字符串”的兼容性查看。一个代替计划是应用 getSubscriptionId()) 办法,它会针对设施上指定的 SIM 卡信息返回一个以数字 1 结尾的惟一索引值,也就是说,如果同一张 SIM 卡被重新安装到设施上的话,它会放弃之前的订阅标识符,除非设施复原出厂设置。更多请参阅:惟一标识符最佳做法。
平台和 Google Play 服务为利用提供了一些其它的 标识符,提供各种唯一性、可重置性和有作用域限度的标识符,实用于各种不同的利用场景。更多请参阅:惟一标识符最佳做法。
以上内容可能帮忙大家更快更新适配最新的 API,并设计出对隐衷更敌对的利用。更多资源请参阅:
- Android 11 中的改良
- 隐衷设置最佳实际