权限管理:Android权限模型演进、最小权限原则、运行时权限处理、自定义权限

聊到Android安全,权限管理绝对是个绕不开的话题。我做了这么多年安全开发,见过太多因为权限处理不当引发的安全事故。说白了,权限就是应用和系统之间的一道门——门开多大,什么时候开,开完要不要关上,这些都得想清楚。

Android权限模型的演进

Android的权限模型不是一天建成的。它经历了几个重要阶段,每个阶段都是为了解决上一阶段的问题。

版本 权限模型 核心特点
Android 1.0 - 5.1 安装时授权 安装时一次性授予所有权限,无法撤销
Android 6.0 - 9.0 运行时权限 用户可在使用中授权或拒绝,可随时撤销
Android 10+ 受限权限 + 分区存储 后台位置、文件访问等进一步收紧
Android 11+ 自动重置权限 长时间未使用的应用,权限自动重置

我记得刚入行那会儿,Android 4.4 还是主流。那时候权限管理简单粗暴——用户要么全给,要么不装。很多应用趁机要了一堆跟功能无关的权限。比如一个手电筒应用,居然要读取联系人权限。这合理吗?显然不合理。

为什么会这样?因为早期开发者习惯了「想要什么就拿什么」的思维。直到 Android 6.0 推出运行时权限模型,整个行业才被迫改变。

最小权限原则

最小权限原则,说白了就是「够用就好」。你的应用只需要完成功能所必需的最小权限集合,多一个都不要。

核心思想:每个模块只拥有完成其任务所必需的最小权限,不多不少。

我在项目中遇到过这样一个案例:一个图片编辑应用,申请了 CAMERAREAD_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGEACCESS_FINE_LOCATION 四个权限。但仔细一分析,定位权限根本用不上。为什么还要申请?产品经理说「以后可能要用」。嗯,这种「以防万一」的心态,恰恰是安全漏洞的温床。

如何落实最小权限原则?我建议从这几个方面入手:

  • 逐功能审查:每个功能模块单独列出需要的权限,去掉冗余项
  • 权限分组:将权限按功能模块划分,避免一个模块的权限被另一个模块滥用
  • 动态检查:运行时检查权限是否被撤销,而不是假设权限一直有效
  • 权限降级:如果某个功能不需要精确权限,就用模糊权限替代

我的习惯:每次提交代码前,我都会打开 AndroidManifest.xml 看一眼,问自己三个问题——这个权限真的需要吗?有没有更低权限的方案?用户会不会觉得这个权限很奇怪?

运行时权限处理

运行时权限是 Android 6.0 引入的核心机制。它把授权时机从「安装时」移到了「使用时」。用户可以在使用某个功能时决定是否授权,也可以随时去设置里撤销。

处理运行时权限,我总结了一套标准流程:

  1. 检查权限:调用 ContextCompat.checkSelfPermission() 检查当前状态
  2. 解释原因:如果用户之前拒绝过,用 shouldShowRequestPermissionRationale() 判断是否需要解释
  3. 发起请求:调用 ActivityCompat.requestPermissions() 弹出系统对话框
  4. 处理回调:onRequestPermissionsResult() 中处理用户的决定
  5. 处理拒绝:如果用户拒绝且勾选「不再询问」,引导用户去设置页面手动开启
// 一个标准的运行时权限请求示例
private void requestCameraPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        
        // 用户之前拒绝过,需要解释
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.CAMERA)) {
            // 弹出自定义对话框解释为什么需要相机权限
            showPermissionExplanationDialog();
        } else {
            // 直接请求权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.CAMERA},
                    REQUEST_CAMERA_PERMISSION);
        }
    } else {
        // 权限已授予,直接打开相机
        openCamera();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
        @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION) {
        if (grantResults.length > 0 
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            openCamera();
        } else {
            // 用户拒绝了权限
            showPermissionDeniedMessage();
        }
    }
}

注意:千万不要在 onCreate() 里一股脑请求所有权限。用户刚打开应用就被一堆权限弹窗轰炸,大概率会直接卸载。我曾经见过一个应用,启动时连续弹出 5 个权限请求,用户连界面都没看到就被劝退了。

自定义权限

有时候,系统提供的权限不够用。比如你的应用需要暴露一个组件给其他应用调用,但又不想让所有应用都能调用。这时候就需要自定义权限。

自定义权限的定义很简单,在 AndroidManifest.xml 中声明即可:

<permission
    android:name="com.example.myapp.permission.MY_CUSTOM_PERMISSION"
    android:label="我的自定义权限"
    android:description="用于访问我的应用的敏感功能"
    android:protectionLevel="dangerous" />

这里有个关键点——protectionLevel。它决定了权限的保护级别:

保护级别 说明 使用场景
normal 低风险,系统自动授予 不涉及用户隐私的功能
dangerous 高风险,需要用户确认 涉及用户隐私或敏感数据
signature 仅同签名应用可获取 自家应用之间的通信
signatureOrSystem 系统应用或同签名应用 系统级功能

我个人最常用的是 signature 级别。为什么?因为它不需要用户交互,而且只有跟你签名一致的应用才能访问。说白了,这就是「自己人」的通行证。

使用自定义权限时,调用方需要在 AndroidManifest.xml 中声明 <uses-permission>

<uses-permission android:name="com.example.myapp.permission.MY_CUSTOM_PERMISSION" />

而被调用的组件(比如 Activity 或 Service)需要设置 android:permission 属性:

<activity
    android:name=".SensitiveActivity"
    android:permission="com.example.myapp.permission.MY_CUSTOM_PERMISSION">
    <intent-filter>
        <action android:name="com.example.myapp.action.SENSITIVE_ACTION" />
    </intent-filter>
</activity>

避坑指南:我曾经犯过一个错误——自定义权限的 protectionLevel 设成了 normal,结果任何应用都能调用我的敏感组件。后来我改成 signature 才解决问题。记住,自定义权限的级别一定要跟实际风险匹配。

知识体系总览

下面这张图梳理了本章的核心知识点,方便你快速回顾:

Android 权限管理知识体系 权限模型演进 安装时授权 → 运行时权限 → 受限权限 → 自动重置 最小权限原则 逐功能审查 权限分组管理 动态检查撤销 权限降级策略 运行时权限处理 检查权限状态 解释权限原因 发起权限请求 处理拒绝逻辑 自定义权限 声明权限 设置保护级别 调用方声明 组件绑定权限 核心目标:保护用户隐私 + 保障功能正常 + 提升用户体验 权限管理不是一次性工作,而是贯穿整个开发周期的持续关注点 理解历史演进 坚持最小原则 规范处理流程

权限管理这件事,说难不难,说简单也不简单。关键在于养成习惯——每次加权限前多问一句「真的需要吗」,每次处理权限请求时多想一步「用户会怎么想」。你想想看,如果每个开发者都这么做,Android 生态的安全水平会提升一大截。


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