第一章 Android权限系统概述
本章从底层机制出发,梳理Android权限系统的分类、运行时请求流程以及状态回调链路,为后续使用Flow监听权限变化打下扎实的基础。只有理解系统层权限状态的分发方式,才能正确地在Jetpack层包装出响应式监听方案。
1.1 权限分类
Android权限按保护级别分为普通权限(Normal)、危险权限(Dangerous)strong>和特殊权限(Special)strong>三类。普通权限在安装时隐式授予,不会向用户弹窗;危险权限需运行时申请,用户可拒绝;特殊权限(如SYSTEM_ALERT_WINDOW、MANAGE_EXTERNAL_STORAGE)需跳转系统设置页面授予。
按功能分组:危险权限以组(Permission Group)为单位呈现给用户。授予组内任一权限时,系统会自动授予同一组中已声明的其他权限。跨组权限则必须单独申请。
| 权限类别 | 授予方式 | 可撤销 | 运行时弹窗 |
|---|---|---|---|
| 普通(Normal) | 安装时自动 | 否 | 否 |
| 危险(Dangerous) | 运行时请求 | 是 | 是 |
| 特殊(Special) | 系统设置 | 是 | 否(跳转页面) |
1.2 运行时请求流程
运行时请求权限的核心类是ActivityCompat与ActivityResultContracts(推荐)。基本流程如下:
- 检查权限状态:使用
ContextCompat.checkSelfPermission()判断是否已授予。 - 解释原因(可选):若需要说明为何申请,调用
shouldShowRequestPermissionRationale()返回true时展示引导。 - 发起请求:通过
ActivityResultLauncher启动系统权限对话框。 - 处理结果:回调返回GRANTED或DENIED,若勾选“不再询问”则后续请求直接失败。
// Kotlin 示例:使用 ActivityResultContracts.RequestPermission
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// 权限已授予
} else {
// 权限被拒绝
}
}
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
适配要点:Android 11+ 允许用户在权限对话框中选择“仅本次允许”,开发者需监听PackageManager.PERMISSION_GRANTED状态,而非假定一次性授予。
1.3 权限状态回调机制
系统通过两种方式通知应用权限变化:
- Activity.onRequestPermissionsResult()(已过时)
- ActivityResultCallback(推荐,基于
ActivityResultContracts)
当用户从系统设置页手动修改权限时,Activity不会直接收到回调,而是通过onResume()时重新检查。危险权限的grant state存储在PackageManager中,任何授予/撤销操作都会触发PackageManager内部的权限状态变更广播(ACTION_PERMISSION_GRANT_CHANGED),但该广播仅限系统应用捕获。普通应用需要依赖运行时重新检查或生命周期回调。
关键限制:Android没有公开的“监听所有权限变化”的API。若要观察单一权限,必须轮询checkSelfPermission()或监听系统设置页返回后的onResume。这正是本课程引入Flow + Lifecycle封装的原因。
1.4 性能与稳定性注意事项
- 频繁调用
checkSelfPermission()(如每帧)会触发Binder IPC,应避免在主线程密集调用。 - 在
onResume()中检查权限是安全的,但需防止无限制的“检查-弹窗”循环(用户选择不再询问时弹窗消失)。 - 使用
ActivityResultContracts.RequestMultiplePermissions一次申请多个权限,减少对话框次数。
调试技巧:在开发者选项中关闭“权限监控”或通过adb shell pm revoke 手动撤销权限,验证回调是否正确触发。