第一章 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(推荐)。基本流程如下:

  1. 检查权限状态:使用ContextCompat.checkSelfPermission()判断是否已授予。
  2. 解释原因(可选):若需要说明为何申请,调用shouldShowRequestPermissionRationale()返回true时展示引导。
  3. 发起请求:通过ActivityResultLauncher启动系统权限对话框。
  4. 处理结果:回调返回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封装的原因。

权限状态流转与回调机制 应用启动 checkSelfPermission 已授权? 直接使用 请求权限对话框 用户决策 onActivityResult 设置页手动更改 → 无回调

1.4 性能与稳定性注意事项

  • 频繁调用checkSelfPermission()(如每帧)会触发Binder IPC,应避免在主线程密集调用。
  • 在onResume()中检查权限是安全的,但需防止无限制的“检查-弹窗”循环(用户选择不再询问时弹窗消失)。
  • 使用ActivityResultContracts.RequestMultiplePermissions一次申请多个权限,减少对话框次数。

调试技巧:在开发者选项中关闭“权限监控”或通过adb shell pm revoke 手动撤销权限,验证回调是否正确触发。