Android 权限模型概览
Android 权限模型是应用访问受限资源(如相机、位置、联系人)的门禁系统。自 Android 6.0(API 23)起,权限模型从“安装时授予”演变为“运行时授予”,大幅提升了用户对隐私的控制力。本章从原理层面拆解权限分类、保护级别,并对比运行时权限与安装时权限的本质区别。
1.1 权限分类
Android 将权限划分为三类,按声明方式和授予时机区分:
- 普通权限 (Normal Permission):风险较低,系统自动授予,无需用户交互。例如
INTERNET、ACCESS_NETWORK_STATE。 - 危险权限 (Dangerous Permission):涉及用户隐私或设备安全,必须运行时明确申请。例如
CAMERA、ACCESS_FINE_LOCATION。 - 签名权限 (Signature Permission):只有使用相同证书签名的应用才能获取,用于系统级或同厂商应用通信。例如
BIND_ACCESSIBILITY_SERVICE。
1.2 保护级别 (Protection Level)
每个权限在 AndroidManifest.xml 中声明时都包含一个 protectionLevel 属性,它决定了权限的授予策略。常用保护级别如下:
| 保护级别 | 含义 | 授予时机 |
|---|---|---|
normal |
低风险,系统自动授予 | 安装时 |
dangerous |
高风险,需用户确认 | 运行时 |
signature |
仅同签名应用可申请 | 安装时 |
signatureOrSystem |
系统应用或同签名应用 | 安装时 |
在代码中,保护级别常通过 PermissionInfo 的 protectionLevel 字段获取:
// 获取权限信息
PackageManager pm = getPackageManager();
PermissionInfo info = pm.getPermissionInfo("android.permission.CAMERA", 0);
int level = info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
if (level == PermissionInfo.PROTECTION_DANGEROUS) {
// 危险权限,需要运行时申请
}
1.3 运行时权限 vs 安装时权限
两者核心差异在于授予时机、用户交互及撤销机制:
| 对比维度 | 安装时权限(Android < 6.0) | 运行时权限(Android 6.0+) |
|---|---|---|
| 授予时机 | 应用安装时一次性授予 | 应用运行时弹窗请求 |
| 用户交互 | 安装前列表展示,用户确认安装即同意 | 每次使用前弹窗,用户可拒绝 |
| 撤销方式 | 只能通过卸载或设置中的“清除数据” | 用户在设置中随时可关闭 |
| 适用于 | 普通权限 + 签名权限 | 危险权限 |
| 代码影响 | 调用敏感 API 时无需检查 | 每次调用前需检查并申请 |
常见错误:在 Android 6.0+ 设备上,若
targetSdkVersion < 23,即使声明了危险权限,系统也会在安装时自动授予,导致运行时不弹窗。这是许多旧应用在 Android 10+ 上崩溃的根源之一。
1.4 权限声明与清单配置
所有权限(无论哪种类型)都必须在 AndroidManifest.xml 中声明:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="32" />
<application ...>
...
</application>
</manifest>
系统在安装时扫描 <uses-permission> 标签,并依据保护级别决定后续策略。注意 maxSdkVersion 可限制该权限在高于某 API 版本后不再生效,适用于位置权限等逐渐被细化的场景。
性能与优化提示:运行时权限请求涉及 Activity 生命周期、Dialog 弹窗、用户等待。若一个页面同时请求多个危险权限,建议使用
requestPermissions 批量申请,并合理处理 onRequestPermissionsResult 回调,避免频繁弹窗导致用户体验下降。
1.5 常见错误与调试
- 权限未声明:运行时报
SecurityException,Logcat 中可见Permission Denial。始终检查清单文件。 - targetSdkVersion 过低:即使运行时申请也会被系统忽略(自动授予),导致在 Android 11+ 出现兼容性问题。
- 权限组误解:危险权限按组管理,申请组内任一权限,用户同意后该组其他权限自动授予。例如申请
CAMERA时,如果同一个组内有RECORD_AUDIO(实际上它们不在同一组),需注意分组查看。
调试命令:使用 ADB 列出应用已授予的权限:
使用
adb shell dumpsys package com.example.myapp | grep -A 100 "grantedPermissions"使用
pm revoke 模拟撤销权限:adb shell pm revoke com.example.myapp android.permission.CAMERA