Android 权限查询

60 多条常用权限的保护级别、权限组、引入版本与废弃情况都在这里。勾选需要的权限,直接拿到能粘进 AndroidManifest.xml 的声明片段;危险的权限还会附一段运行时申请的 Kotlin 代码。

显示 67 / 67 条,已选 0 条

使用说明

这张表按「查得到、看得懂、拷得走」来组织:每条权限给出常量全名、中文名、一句话说明,再标注保护级别、是否需要运行时申请、所属权限组和引入版本。保护级别用的是归档后的五类——普通、危险、签名、签名或系统、特殊。普通权限装上就有,只要在 manifest 里声明;危险权限涉及隐私数据,从 Android 6.0(API 23)起必须在代码里申请;签名权限只有与系统同签名的应用才拿得到,第三方应用写了也不会被授予;特殊权限是我为了区分「要跳设置页单独开关」这一类而单独归的,官方文档里多写成 signature|appop 之类的组合值,凡是拿不准的条目都标了「请以官方文档为准」。

运行时权限的完整链路是「manifest 声明 + 代码申请 + 用户同意」三步,少任何一步都拿不到权限,而且失败的方式还不一样:manifest 没声明时申请会被系统直接拒绝,连对话框都不弹;代码里没申请时 checkSelfPermission 一直是 denied;用户拒绝过两次或勾了「不再询问」之后,再申请也不会弹框,只能自己判断并跳应用设置页。判断方法是用 shouldShowRequestPermissionRationale:返回 true 说明还能再弹一次,可以和用户解释用途;返回 false 而权限又没授予,那就是被永久拒绝了。页面里生成的 Kotlin 片段只负责第二步,声明部分由上面的 manifest 片段补齐。

权限组与「同组自动授予」这个坑

权限组是系统为了少弹对话框而做的分组,它带来过一个很常见的误判。Android 8.0(API 26)以前,同一组里只要有一条权限被授予,同组的其他权限会被一并标记为已授予;Android 8.0 起收紧了:系统只授予你当次申请的那一条,但之后再去申请同组权限会静默通过、不再弹框,于是「没单独申请却也到手了」的现象依然存在。开发者在代码里申请了两条同组权限、看到两条都通过,就以为自己的申请逻辑生效了,其实第二条是随组赠送的。Google 官方现在明确说不要依赖分组,因为组内成员随时可能调整,再加上各厂商 ROM 的差异,正确做法是按功能逐条声明、逐条申请;反过来也要注意,用户在设置里关掉「联系人」整组时,你依赖的那几条也会一起失效。表里的权限组列保留官方分组名只为方便对照,不代表组内权限可以互相代替。

存储与位置这两块变化最大

存储权限是十几年里改动最多的一块。READ_EXTERNAL_STORAGE 与 WRITE_EXTERNAL_STORAGE 曾经是标配,如今:Android 10 引入分区存储,应用往自己的目录、媒体集合、下载目录写文件不再需要写权限;Android 11 起 targetSdk 30 的应用申请 WRITE_EXTERNAL_STORAGE 也不再被授予;Android 13 起 targetSdk 33 的应用申请 READ_EXTERNAL_STORAGE 会被直接忽略,读图片、视频、音频分别改用 READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO,Android 14 又补了「选中部分照片」的 READ_MEDIA_VISUAL_USER_SELECTED。所以兼容写法的核心就是用 android:maxSdkVersion 把旧权限限制在老系统上,让新系统只看到新的权限。

位置权限则是在「精度」和「时长」两个维度被不断细分:精度上,Android 12 起用户可以在对话框里选择只给大致位置,此时只有 ACCESS_COARSE_LOCATION 被授予;时长上,Android 10 拆出 ACCESS_BACKGROUND_LOCATION,Android 11 起「仅这一次」的授权会在应用退到后台一段时间后被收回,而后台位置必须单独引导用户去设置页选「始终允许」,不能和前台位置一起申请。做地图、跑步、打卡这类功能时,先想清楚「退到后台还要不要定位」,再决定要不要碰后台权限。

怎么确认自己手上这台设备到底怎么判

文档与设备实际行为有时会有差距,尤其是厂商 ROM 和较新的 Android 版本。下面的命令可以通过 adb 直接查设备上的真实情况,比任何速查表都准;表里的保护级别、是否需要运行时申请这些结论也都应该以设备输出和官方文档为准。另外提醒一句:权限是应用能在系统里做什么的开关,不是数据安全的边界——装在用户设备上的应用,客户端拿到的密钥和接口地址最终都是可以被人翻出来的,敏感的判定逻辑要放在服务端。

用 adb 自查设备权限状态的命令
用途命令复制
看设备系统版本与 API 级别 两条属性分别给出 Android 版本号与 API 级别,判断权限行为要看的是 API 级别。adb shell getprop ro.build.version.release; adb shell getprop ro.build.version.sdk
看某条权限的保护级别 在权限相关的输出里能看到 protectionLevel,这是设备实际认的级别,比文档更贴近手上的这台机器。adb shell dumpsys package android.permission.CAMERA
看某个应用拿了哪些权限 列出的 granted=true / false 就是运行时权限的实际状态,排查「明明申请了却没生效」时最有用。adb shell dumpsys package com.example.app | grep -A 40 "runtime permissions"
临时授予签名级权限 调试时才有效,重启或重新安装后会失效;用于验证权限本身而不是绕过它。adb shell pm grant com.example.app android.permission.WRITE_SECURE_SETTINGS

最后补一句关于时效性:权限的行为几乎每个大版本都在动,这张表以 Android 13 及之后的版本为准整理,凡是我没有把握的地方都标了「请以官方文档为准」,核对时优先看 Android 开发者文档里权限那一节的 Added in / protectionLevel,以及各版本的「行为变更」说明。权限相关的调试经常要连着看接口返回,需要把请求转成 curl 或代码可以用curl 转代码,适配不同屏幕密度和分辨率可以用屏幕分辨率查询。

五个保护级别分别意味着什么

保护级别的含义与申请方式
级别条数含义与申请方式
普通21装上就生效,只要在 manifest 里声明
不需要运行时申请
危险37涉及隐私数据,Android 6.0 起必须运行时申请
需要运行时申请,且必须在 manifest 里声明
签名2只有与系统同签名的应用才能拿到,第三方应用申请也拿不到
不需要运行时申请,写了也没用
签名或系统0系统镜像里的应用,或与平台同签名的应用
不需要运行时申请
特殊7不能靠对话框申请,要跳到设置里由用户手动开关(AppOps)
不走运行时权限对话框,需要跳设置页

签名或系统这一类权限基本不会出现在普通应用的清单里,本表没有收录条目;表里出现的分组说明同样只作对照用。

权限组的中文名与覆盖范围
权限组条数覆盖范围
存储4读写外部存储与媒体文件,Android 13 起被细分成媒体权限
位置3前台与后台定位,Android 10 起拆出后台定位
相机1拍照与录像,不含只读取相册
麦克风1录音与语音输入
联系人3读取与写入通讯录、账户列表
日历2读取与写入日程
短信5收发短信、彩信与 WAP 推送
电话4拨号、读取电话状态与号码
通话记录3读写通话记录,Android 9 起移出电话组
身体传感器3心率等来自体表传感器的数据
身体活动1计步与运动识别,Android 10 起独立成组
媒体4Android 13 起细分的图片、视频、音频读取权限;官方把图片与视频归在 READ_MEDIA_VISUAL、音频单独归在 READ_MEDIA_AURAL 两个组里,表里为便于阅读统称媒体
附近设备5蓝牙扫描与连接,Android 12 起取代旧蓝牙权限
附近 Wi-Fi 设备1Android 13 起管理 Wi-Fi 设备发现
通知1Android 13 起发通知也要用户同意
系统与常规18网络、唤醒锁这类装上就能用的普通权限
特殊权限8悬浮窗、修改系统设置这类要在设置页单独开关的权限

常见问题

只申请了读取联系人,为什么写入联系人也直接通过了?

这是权限组的老行为:同一组里只要有一条被授予,同组的其他权限会被系统一并标记为已授予。它从 Android 8.0(API 26)起收了紧——系统只授予你当次申请的那一条,但之后再申请同组权限会静默通过、不再弹框,所以给人的感觉依然像「没单独申请也到手了」。存储组、联系人组、位置组最容易撞上这个坑,很多人因此误以为是自己代码里的两条申请都生效了。Google 官方明确说过不要依赖分组,因为组内成员随时可能调整;正确做法是按功能逐条声明、逐条申请自己真正需要的权限。

manifest 里声明了权限,运行时还是拿不到,为什么?

两件事得同时成立:manifest 里声明,代码里申请。危险权限从 Android 6.0(API 23)起必须用 requestPermissions 或 ActivityResult API 主动申请,只写 manifest 不会自动授予;反过来,manifest 里没声明的权限再怎么申请都会被系统直接拒绝,而且不会弹任何对话框。用户点了拒绝之后还有一层:可以继续申请的(能再弹一次)和「不再询问」的(后面必须跳应用设置页),判断方法是看 shouldShowRequestPermissionRationale 是否返回 false。

targetSdk 跟权限有什么关系,为什么升级 targetSdk 之后权限行为就变了?

系统的权限与存储行为是按应用的 targetSdk 决定的,不是按设备的系统版本。targetSdk 33 的应用申请 READ_EXTERNAL_STORAGE 会被直接忽略,只能改用 READ_MEDIA_IMAGES 这类媒体权限;targetSdk 30 起分区存储强制生效,写公共目录必须走 MediaStore。所以「同一个权限在旧项目里好使、新项目里不行」通常不是设备问题,而是 targetSdk 升级触发了新规则。

Android 13 起读取相册到底该申请哪几条权限?

读图片用 READ_MEDIA_IMAGES,读视频用 READ_MEDIA_VIDEO,两条是独立的,用户可以只同意其中一条。要兼容旧系统就同时保留 READ_EXTERNAL_STORAGE,并用 android:maxSdkVersion="32" 把它限制在 Android 12L 及以前生效,这样新系统上它不会参与申请。音频要单独用 READ_MEDIA_AUDIO。Android 14 又多了「选中部分照片」,用户只授权选中的那几张时得到的是 READ_MEDIA_VISUAL_USER_SELECTED。

「仅在使用时允许」「仅这一次」「始终允许」分别在什么时候出现?

位置权限的对话框从 Android 11(API 30)开始提供「仅这一次」,授权只在本次前台会话内有效,应用退到后台一段时间后会被收回;「仅在使用时允许」对应前台位置;「始终允许」对应 ACCESS_BACKGROUND_LOCATION,从 Android 11 起不能和前台位置一起申请,只能先拿到前台位置,再单独引导用户去设置页选。Android 12 起用户还能在对话框里选择只给大致位置,于是 ACCESS_FINE_LOCATION 可能被拒而 ACCESS_COARSE_LOCATION 被授予,代码必须两种精度都能跑。

后台位置权限为什么一直申请失败?

因为它不能通过权限对话框拿到。Android 11 起 ACCESS_BACKGROUND_LOCATION 必须单独申请,系统会直接把用户带到设置页,在那里手动选「始终允许」;如果和前台位置一起申请,这次申请会被系统整体忽略。另外从 Android 11 左右开始,很多厂商 ROM 还会额外做一层后台限制,即使设置里选了「始终允许」,应用仍可能因为电池优化策略被限制定位,这类问题需要结合后台耗电白名单一起看。

模拟器或调试机上能用的权限,为什么上线就失败?

常见原因是权限级别不对。签名级权限(例如 REBOOT、WRITE_SECURE_SETTINGS)只有与系统同签名的应用才拿得到,调试时可以用 adb shell pm grant 临时授予,所以在本机测试通过,装到正式签名包里立刻就失败。另一类原因是分发渠道的政策:短信、通话记录、所有文件访问、查询所有应用、精确闹钟这类权限,即使技术上申请得到,上架审核也可能直接拒绝,得先用不影响功能的方案替代。

表里带「请以官方文档为准」标记的条目是什么意思?

表示这一条的保护级别或版本细节我没法百分百确定,例如特殊权限在官方文档里写作 signature|appop 这类组合值、Android 14 新增的媒体权限级别写法还在变化。与其按记忆写一个可能过时的结论,不如明确标出来。核对的办法是在自己的设备上跑 adb shell dumpsys package 加权限名,输出里的 protectionLevel 就是这台机器实际认的级别,比任何第三方速查表都可靠;接口联调时把请求转成 curl 或代码也可以用命令行工具配合。

相关:curl 转代码