1. 权限基础:Android权限模型演进、普通权限与危险权限、权限组概念

各位同学好,我是老张。今天咱们聊聊Android权限的基础知识。说实话,权限这块我踩过的坑真不少——早期项目里因为权限问题导致App在某个厂商手机上直接闪退,那叫一个尴尬。嗯,咱们从最基础的开始讲起。

1.1 Android权限模型的演进

Android的权限模型,说白了就是一套「App能干什么、不能干什么」的规则。我刚开始做Android开发那会儿,还是Android 4.4的时代,那时候权限管理相当粗放。

核心演进路线:

  • Android 1.0 - 5.0(安装时授权):用户安装App时,系统会列出所有权限。你点「安装」,就等于一次性全同意了。之后App想干嘛就干嘛,没法撤销。
  • Android 6.0(运行时权限诞生):这是里程碑式的变化。敏感权限必须在运行时弹窗询问用户,用户可以选择「允许」或「拒绝」。我记得当时适配这个改动,整个团队加班了两周。
  • Android 10 - 13(精细化管控):新增「仅在使用中允许」「本次允许」「后台位置」等选项。权限越来越细,用户控制力越来越强。

为什么会这样演进?你想想看,早期那种「一刀切」的方式,用户根本不知道App在后台干了什么。有些流氓App装上就开始偷通讯录,用户毫无办法。所以Google不得不一步步收紧权限。

1.2 普通权限与危险权限

Android把权限分成了两大类:普通权限(Normal Permissions)危险权限(Dangerous Permissions)。这个分类直接决定了你的App需不需要处理运行时弹窗。

类型 特点 举例 是否需要运行时申请
普通权限 不直接威胁用户隐私,系统自动授予 INTERNET、ACCESS_NETWORK_STATE、VIBRATE 否,只需在Manifest声明
危险权限 涉及用户隐私数据或敏感功能 CAMERA、READ_CONTACTS、ACCESS_FINE_LOCATION 是,必须运行时弹窗申请

我的经验:普通权限虽然不用运行时申请,但千万别在Manifest里乱写。我曾经见过一个项目,把几十个普通权限全列上了,结果用户一看权限列表直接卸载了App。只声明你真正需要的权限,这是基本原则。

危险权限的申请流程,我建议你这样理解:

  1. 检查权限是否已被授予(checkSelfPermission)
  2. 如果未授予,判断是否需要展示解释说明(shouldShowRequestPermissionRationale)
  3. 发起权限请求(requestPermissions)
  4. 在回调中处理用户的选择(onRequestPermissionsResult)
// 一个标准的危险权限申请代码片段
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED) {
    // 权限未授予,需要申请
    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.CAMERA)) {
        // 这里可以展示一个解释说明,告诉用户为什么需要这个权限
        showPermissionRationaleDialog();
    } else {
        // 直接申请权限
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CAMERA},
                REQUEST_CODE_CAMERA);
    }
} else {
    // 权限已授予,直接执行相机操作
    openCamera();
}

注意:千万不要在onRequestPermissionsResult里只处理「允许」的情况。用户拒绝后,你的App应该能优雅降级,而不是直接崩溃。我曾经见过一个App,用户拒绝位置权限后,整个地图页面白屏——这就是典型的没做好异常处理。

1.3 权限组概念

权限组(Permission Group)是Android用来管理同类权限的一种机制。说白了,就是把功能相似的权限归到一个组里。比如「通讯录」这个组,包含了READ_CONTACTS和WRITE_CONTACTS两个权限。

权限组的核心规则:

  • 如果用户同意了某个权限组里的一个权限,系统会自动授予该组里的所有权限(仅限同组且已在Manifest中声明的)
  • 如果用户拒绝了某个权限,再次申请同组其他权限时,系统会直接拒绝,不会弹窗

举个例子:你的App声明了READ_CONTACTS和WRITE_CONTACTS。用户同意了READ_CONTACTS,那么WRITE_CONTACTS也会自动被授予,不需要再次弹窗。反过来,如果用户拒绝了READ_CONTACTS,你再申请WRITE_CONTACTS,系统会直接回调拒绝,连弹窗都不显示。

重要提醒:这个规则在Android 11之后有所变化。Google开始弱化权限组的概念,建议开发者不要依赖「同组自动授权」的行为。我建议你每个权限都独立申请、独立检查,别偷懒。

1.4 知识体系总览

下面这张图是我自己整理的权限基础知识结构,你可以对照着理解:

Android权限基础体系 权限模型演进 安装时授权(1.0-5.0) 运行时权限(6.0) 精细化管控(10-13) 权限分类 普通权限(系统自动授予) 例:INTERNET、VIBRATE 危险权限(需运行时申请) 例:CAMERA、READ_CONTACTS 权限组:同类权限归组管理,同组授权自动同步

这张图把权限基础的三块内容串起来了。从上往下看:先了解权限模型怎么演进的,再搞清楚普通和危险权限的区别,最后理解权限组的作用。我个人习惯把这张图贴在工位上,每次做权限适配时扫一眼,思路就很清晰。

避坑指南:我曾经在适配Android 12时,发现某个厂商的ROM把「存储权限」从危险权限改成了普通权限。结果我的App按照标准流程申请,反而出了问题。所以记住:不要假设所有设备的行为都完全一致,一定要做充分的兼容性测试。

好了,权限基础就讲到这里。记住三个关键词:演进、分类、分组。搞懂这些,后面学运行时权限申请流程就会轻松很多。


公众号:蓝海资料掘金营,微信deep3321