在Android 6.0 设备上动态获取权限
Android 6.0(API 23)起,危险权限改成运行时授权:安装时不再一揽子通过,真正用到电话、短信、相机时才弹窗。本篇用拨号(
CALL_PHONE)走一遍检查、申请和回调。
一、先写出拨号
拨号本身还是一个 Intent。注意是 ACTION_CALL(直接拨出),不是打开拨号盘的 ACTION_DIAL:
Manifest 里仍要声明权限,运行时申请并不能代替这一行:
二、为什么在 6.0 上会崩溃
Android 6.0 之前,上面代码没问题。若设备已是 6.0,且 targetSdkVersion 设为 23,一点拨号就会崩。
把 targetSdkVersion 降到 23 以下,程序不会崩,但在 6.0 设备上依旧拨不了电话。权限机制是 Android M 才加入的:从 M 开始,声明过的权限要在运行时动态授予。要兼容 6.0,必须在代码里检查并申请,而不是只改 target。
动态分配细节可看原文 权限动态分配;只想看做法可跳到 解决方案。
三、安装时授权 vs 运行时授权
6.0 之前,安装界面会列出应用索要的全部权限:

上图分别是 Nexus 6 和小米在安装时的界面。点「接受 / 安装」就等于一次授权全部声明权限。很少有人会因为某一条敏感权限而放弃安装——那时用户还没真正去读通话记录或短信。
更合理的时机是:应用马上要读短信时,系统弹出提示,用户结合当前场景决定给不给。不给会怎样、给了会怎样,都由用户主动判断。这比安装时那一勾更尊重隐私。
MIUI 很早就做了运行时授权,比官方 Android 更早落地。
直到 Android 6.0,Google 才把这套做成系统能力:安装时仍提示会用到哪些权限;真正获取敏感权限时再弹窗。例如读短信:

官方说明大意:从 Android 6.0(API 23)起,用户在应用运行过程中授权,而不是安装时一次性授予。安装更轻,用户也能按功能拆开权限——比如只给相机、不给定位,随时可在系统设置里收回。
| 对比 | Android 6.0 之前 | Android 6.0(target 23) |
|---|---|---|
| 授权时机 | 安装时一次性同意全部 | 用到危险权限时再弹窗 |
| 只声明不申请 | 一般可直接调用 | 可能崩溃或功能被拒 |
| 用户反悔 | 卸载或改系统设置(因 ROM 而异) | 设置里可随时撤销 |
| 取巧降 target | 无此问题 | 不崩,但拨号等能力仍可能不可用 |
四、检查、申请、回调
对版本做判断,6.0 走兼容分支:
6.0 用户触发拨号时,会看到 Material 风格的系统对话框:

requestPermissions 的最后一个参数是 requestCode,类似 onActivityResult。申请之后要在当前 Activity 实现 onRequestPermissionsResult:
用 grantResults[0] 判断用户点了允许还是拒绝,再走拨号或提示。
五、有用的链接
上面只是拨号这一条权限的最小示例。更完整的运行时权限说明见:
-
Everything every Android Developer must know about new Android’s Runtime Permission(英文长文) -
已有中译:翻译链接 -
处理 6.0 权限兼容的开源库:PermissionHelper
出自 咕咚 的博客:在Android 6.0 设备上动态获取权限
一句话总结:target 23 之后危险权限要 checkSelfPermission → requestPermissions → onRequestPermissionsResult,只降 target 不崩也拨不了电话。
转载请注明来源:在Android 6.0 设备上动态获取权限








