Permission Group Android中的权限分组机制,将功能相关的危险权限组合到一个逻辑类别中。根据Android Permissions Overview, 2024,权限组简化了用户界面:如果用户已经授予了某个组中的一个权限,其他权限将自动被授予,无需额外对话框。这减少了请求数量并改善了UX。
主要观点
Permission Group — 是Android的系统机制,根据功能用途将多个危险权限组合到一个组中。每个组都有一个字符串标识符,例如android.permission-group.CAMERA或android.permission-group.LOCATION。一个组中的所有权限都逻辑相关,提供对设备相关功能的访问。
权限组随Android 6.0 Marshmallow一起出现,同时引入了运行时请求模型。它们的主要目标是简化与用户的交互:替代为每个单独权限弹出一系列对话框,系统为每个组显示一个对话框。如果用户已经授予了某个组中的一个权限,其他权限将被视为自动批准。根据Android UX Research (2015),这将首次启动时的拒绝率降低了20%。
重要的是,开发者无法创建自己的Permission Group。组在操作系统层面预先定义,并在每个设备的permissions.xml文件中描述。应用程序只指定uses-permission,系统会根据protectionLevel和AOSP中的分类自动将权限与其组匹配。
权限与组的匹配通过权限系统定义中的permissionGroup属性完成。例如,CAMERA声明为permissionGroup="android.permission-group.CAMERA",ACCESS_FINE_LOCATION声明为permissionGroup="android.permission-group.LOCATION"。这个映射在Android Open Source Project代码中确定,在所有认证设备上都相同。
组机制按“每组一个对话框”原则工作。当应用程序首次请求任何危险权限时,系统会检查其Permission Group。如果还没有授予该组中的任何权限,则会显示一个对话框。同意后,系统将整个组标记为已授予,并且后续对同一组中其他权限的请求将在没有用户界面的情况下被满足。
简化的算法如下:
这个机制仅适用于危险权限。普通权限没有组,不参与这个逻辑。特权和签名权限也不会被分组——它们有单独的访问管理系统。
组不能反向工作:通过设置撤销组中的一个权限只会撤销该权限,不会影响其他权限。此外,如果用户拒绝了某个组的对话框,这不会阻止其他组——来自另一个组的每个新权限都会显示自己的对话框。Permission Group仅影响请求的UX,而不影响安全模型。
Android定义了以下用于危险权限的系统 Permission Group。每个组包含一个或多个由共同功能目标联合起来的权限。
| 组标识符 | 组中的权限 | 描述 |
|---|---|---|
| CAMERA | CAMERA | 访问设备相机 |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION | 地理位置(精确和近似) |
| MICROPHONE | RECORD_AUDIO | 从麦克风录音 |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG, WRITE_CALL_LOG, ADD_VOICEMAIL, USE_SIP | 电话功能 |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | 访问联系人和账户 |
| SMS | READ_SMS, SEND_SMS, RECEIVE_SMS, RECEIVE_WAP_PUSH, RECEIVE_MMS | 发送和接收SMS |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE | 读写外部存储 |
| CALENDAR | READ_CALENDAR, WRITE_CALENDAR | 访问日历 |
| SENSORS | BODY_SENSORS | 身体传感器(心率和其他) |
| ACTIVITY_RECOGNITION | ACTIVITY_RECOGNITION | 识别身体活动 |
在Android 13(API 33)中出现了一个新组NEARBY_DEVICES,它组合了BLUETOOTH_SCAN、BLUETOOTH_CONNECT和BLUETOOTH_ADVERTISE。此外,STORAGE组部分被媒体权限READ_MEDIA_IMAGES、READ_MEDIA_VIDEO和READ_MEDIA_AUDIO所取代,这些不是STORAGE的一部分,而是没有分组的独立危险权限。
开发者可以通过清单中的permissionGroup属性声明自己的权限,并使用自定义Permission Group。但这仅适用于同一应用程序的自定义权限,不会影响系统UI对话框。在实践中,自定义Permission Group很少使用——用于在同一栈中自己的应用程序之间进行交互。
Permission Group的影响对用户体验很大。由于分组,用户看到的不是针对不同权限的8个单独对话框,而是几个组对话框。这减轻了认知负荷,并降低了用户在不理解其目的的情况下拒绝关键权限的可能性。
UX研究表明,用户觉得组对话框更透明。当应用程序请求“访问相机”时,用户理解上下文。如果每个权限都单独请求——CAMERA、CAMERA2、FLASHLIGHT——这会给人一种冗余的感觉。Permission Group抽象了这种细节。
最佳实践是每次只请求来自一个组的权限。如果应用程序同时需要相机和地理位置,不要通过一个requestPermissions调用来请求它们。先在解释后请求一个组,然后再请求第二个。这给予用户控制权,并逐步理解每个功能。
Permission Group和ProtectionLevel——这是Android权限系统的两个不同维度。ProtectionLevel确定如何授予权限(normal、dangerous、signature、privileged),而Permission Group是用于UI显示的类别。它们独立,但在实践中,dangerous + permission group的组合最为常见。
相同ProtectionLevel的权限可以属于不同的组。例如,ACCESS_FINE_LOCATION和CAMERA都具有protectionLevel dangerous,但属于不同的组——LOCATION和CAMERA。反之亦然,同名的权限始终属于同一个组:ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION都在LOCATION中。
更高级别的保护级别——signature和privileged——不使用Permission Group进行UI显示。它们的授予在系统层面控制:signature授予给与系统使用相同证书签名的应用程序,privileged授予给系统镜像中的应用程序。这类权限的组确实存在,但不会影响UX对话框,因为这些对话框根本不存在。
开发者可以通过PackageManager程序化地确定任何权限的Permission Group。getPermissionInfo方法返回一个PermissionInfo,其中的group字段包含组的字符串标识符。这对于日志记录、分析和自定义权限UI屏幕很有用。
fun getPermissionGroupName(
permission: String
): String? {
return try {
val pm = packageManager
val info = pm.getPermissionInfo(
permission,
PackageManager.GET_META_DATA
)
info.group
} catch (e: NameNotFoundException) {
null
}
}
fun getPermissionsByGroup(
group: String
): List<String> {
val pm = packageManager
val perms = pm.queryPermissionsByGroup(
group,
PackageManager.GET_META_DATA
)
return perms.map { it.name }
}
了解Permission Group有助于構建请求架构。可以创建一个PermissionGroupProvider抽象,它返回特定组的权限列表。这简化了测试:在单元测试中,provider返回伪造数据而不调用PackageManager。在工具测试中,则返回来自系统的真实组。
通过Dagger Hilt或Koin集成PermissionGroupProvider可以集中管理权限和组的映射。在provider中可以缓存PackageManager.queryPermissionsByGroup的结果,以避免每次请求时重复调用系统。这对于显示所有权限及其状态的设置屏幕尤其重要。
在收集关于拒绝的分析数据时,不仅记录权限名称,还记录其Permission Group也很有用。这有助于识别导致最多拒绝的功能域。例如,LOCATION组一向拥有最高的拒绝率——根据Google Play Console统计数据,约为40%。
按组分析有助于做出产品决策:如果CONTACTS组的拒绝率很高,可能需要重新考虑请求时机或添加解释对话框。基于组的分析方法比单独权限分析提供更完整的图景,因为整个组的拒绝数反映了用户对功能域的整体态度。
常见问题
Permission Group — 将功能相关的危险权限组合到一个类别的机制。如果用户已经授予了组中的一个权限,其他权限将自动被授予,无需额外对话框。
标准Android中约有10个主要组:CAMERA、LOCATION、MICROPHONE、PHONE、CONTACTS、SMS、STORAGE、CALENDAR、SENSORS和ACTIVITY_RECOGNITION。Android 13+中添加了NEARBY_DEVICES。
可以,通过AndroidManifest.xml中的permissionGroup属性为自定义权限创建。但这仅适用于应用程序内部的权限,不会影响系统UI对话框。在实践中很少使用。
撤销组中的一个权限不会撤销其他权限。用户可以关闭ACCESS_FINE_LOCATION,但ACCESS_COARSE_LOCATION仍然活跃。组仅影响授予,不影响撤销。
使用PackageManager.getPermissionInfo并读取group字段。该方法返回组的字符串标识符,例如android.permission-group.CAMERA。如果权限没有组,字段将为null。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。