概述
权限的作用是保护Android用戶的隐私。
如果设备搭载的是Android 6.0(API 级别 23)或更高版本,并且应用的targetSdkVersion 是23或更高版本,用戶在安装时不会收到任何应用权限的通知。您的应用必须在运行时请求用戶授予危险权限。当应用请求权限时,用戶会看到一个系统对话框,告知用戶应用正在尝试访问的权限组。该对话框包括拒绝和允许按钮。如果用戶选中不再询问复选框并点按拒绝,当您以后尝试请求相同权限时,系统不会再提示用戶。
如果设备搭载的是Android5.1.1(API级别22)或更低版本,或者应用在任何版本的Android上运行时其targetSdkVersion 是22或更低版本,系统将在安装时自动请求用戶向应用授予所有危险权限
权限保护级别
权限的分类总共有如下几种,先有个总览,本篇文章后面是展开讨论dangerous类型即运行时权限的整体流程。
级别 | 描述 |
---|---|
normal | 如果应用在清单中声明需要普通权限,系统会在安装时自动向应用授予该权限。系统不会提示用户授予普通权限,用户也无法撤消这些权限 |
dangerous | 为了使用危险权限,应用必须在运行时提示用户授予权限 |
signature | 在安装时授予这些应用权限,但仅会在尝试使用某权限的应用签名证书为定义该权限的同一证书时才会授予(即相同签名) |
signatureOrSystem signature | privileged |
这里做Android Framework权限开发的经常会遇到系统app的同事过来问权限问题,我这个app是在/system/app目录下的,并且需要的这个权限是signature级别的;为什么在AndroidManifest声明了之后没有默认授予?可以结合下图总结看下;
运行时权限申请
这里开始看下运行时权限的整体流程;正常应用的权限申请过程如下,先看下应用是如何申请运行时权限,再从应用侧到Framework侧看下去; 更多应用权限请求细节可以参考这里
private fun requestPermmission() {
// 判断是否需要运行时申请权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ContextCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// 判断是否需要对用户进行提醒,用户点击过拒绝&&没有勾选不再提醒时,即拒绝一次时进行提示
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) {
// 给用户予以权限解释, 对于已经拒绝过的情况,先提示申请理由,再通过点击弹出的Dialog进行申请
showDialog("需要打开电话权限直接进行拨打电话,方便您的操作")
} else {
// 无需说明理由的情况下,直接进行申请。如:1.第一次使用该功能(第一次申请权限),2.用户拒绝权限并勾选了不再提醒,3.已授权 这3种情况shouldShowRequestPermissionRationale()返回false
ActivityCompat.requestPermissions(
this, new String[]{
Manifest.permission. CALL_PHONE,}, 1);
}
} else {
// 拥有权限直接进行功能调用
callPhone();
}
}
/**
* 权限申请回调
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
// 根据requestCode判断是那个权限请求的回调
if (requestCode == REQUEST_PERMISSION_CODE_CALL_PHONE) {
// 判断用户是否同意了请求
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
callPhone()
} else {
// 未同意的情况
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) {
// 判断是拒绝一次的情况,则同样先是弹Dialog提示用户,再重新申请权限
showDialog("需要打开电话权限直接进行