requestPermissions和checkSelfPermission源码解析

来源:互联网 发布:mac帧结构 编辑:程序博客网 时间:2024/06/07 20:25

Android在6.0之前采用的是静态权限,什么是静态权限呢?就是你安装的时候会询问你是否允许App内的所有权限,只要有一个拒绝,那么这个App你就无法安装了;6.0开始,采用动态权限管理,也就是说你的App可以先安装,具体使用什么权限的时候再去请求就好了,默认权限是全部禁止的

所以我学Android时候的老师最喜欢把 compileSdkVersion 从23写成22,就是觉得动态申请权限过于麻烦,不如直接授权来的爽快,这是一种不顾及用户体验的差的做法,爽了开发者害了用户,所以我们一定要养成尊重用户的习惯,用户就是我们的上帝,本质上说我们其实也是在销售自己的产品(app)

我看到一篇讲权限管理的文章觉得不错,先推荐给大家

Android 6.0 ActivityCompat权限声明

这篇博客详细讲述了ActivityCompat是如何请求危险权限和优化权限请求的,本篇博客将深入两方法的源码研究下具体如何实现的。

ContextCompat.checkSelfPermission()

Determine whether <em>you</em> have been granted a particular permission.确定是否你授予了指定的权限
》》DelegatingContext类 public int checkPermission(@NonNull String permission, int pid, int uid) {        Checks.checkArgument(!TextUtils.isEmpty(permission), "permission cannot be null or empty");        return this.mRevokedPermissions.contains(permission)?-1:0;    }  private Set<String> mRevokedPermissions = new HashSet();mRevokedPermissions 这个单词翻译过来就是取消的权限,可以引申为没授权的权限,HashSet保证每个权限在Set中都是唯一的,没有重复的权限this.mRevokedPermissions.contains(permission)?-1:0这句话意思就是未授权的权限中是否包含permission权限?如果包含那么说明permission也是未授权所以返回值就是-1,否则的话就是说明该权限已经授权,返回值为0我们经常使用ContextCompat.checkSelfPermission()与 PackageManager.PERMISSION_GRANTED进行比较,打开源码发现public static final int PERMISSION_GRANTED = 0;这一点正好印证了0是表示授权的

ActivityCompat.requestPermissions()

这里写图片描述

Build.VERSION.SDK_INT   表示的是手机的系统版本号,比如Android 7.0表示的就是API 24,所以Build.VERSION.SDK_INT=24,所以权限申请会根据Build.VERSION.SDK_INT的值产生不同的结果当请求权限时会根据手机当前版本号判断走哪个方法:1  如果手机版本号是6.0及以上,那么就走 activity.requestPermissions(permissions, requestCode);2  否则那么就走  ((OnRequestPermissionsResultCallback) activity).onRequestPermissionsResult()

先看2的源码:

这里写图片描述

407到408行获取包管理器,然后去检查App是否具备所申请的权限,怎么形象描述这个过程呢?我们一般都在manifest中把我们的权限加进来,对于6.0以下的手机就去查看manifest有没有权限,有的话就授权,咩有就不授权,所以不会有什么对话框出来要你授权。(我在4.4的手机上测试没有弹出对话框,直接授权的)411行到最后这句话是一个回调用来返回权限的结果,407到408行逐一检查是否具备权限,这个结果就将通过此回调传递给Activity,这里记住回调方法是onRequestPermissionsResult()我们后面再讲

再看1的源码:

这里写图片描述

这里写图片描述

红框是startActivityForResult,结合上面的intent是用来请求权限,什么页面用来请求权限呢?很明显,我们想到的是运行时权限窗口,没错!当你申请权限的时候会弹出一个窗口让你选择是允许还是拒绝,(即使你的compileSdkVersion 小于23但是只要是在23以上的机器上也是出现授权页面而不是自动授权)我把断点打在Intent这句,果然当初弹出的对话框不再弹出既然使用的是startActivityForResult,那说明什么?说明我们无论是拒绝还是接受权限,都会返回到这个类中而且还能拿到拒绝或者授权的信息。难点在在哪个方法里找到回调?首先想到的是onActivityResult,但是抱歉!  protected void onActivityResult(int requestCode, int resultCode, Intent data) {    }这是一个空的方法,没有具体的实现。.........挣扎了好久,终于才想到如何找源码,在这里也和大家分享一下这个思路

不会无缘无故使用标志

举个例子,你定义一个常量SUCCESS=1,很明显这个SUCCESS你要用在很多地方使用,你不使用1,而是使用SUCCESS就是为了确保不同的位置,值是统一的而不是传错0或者1

那么解决这个问题的思路就是:

既然问题停留在startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);REQUEST_PERMISSIONS_WHO_PREFIX   那么去找这个参数的位置。

这里写图片描述

本来onActivityResult应该做的事,Acitivity特殊处理交给了dispatchActivityResult来做

重点看以下这段代码

if (who == null) {            onActivityResult(requestCode, resultCode, data);        } else if (who.startsWith(REQUEST_PERMISSIONS_WHO_PREFIX)) {            who = who.substring(REQUEST_PERMISSIONS_WHO_PREFIX.length());            if (TextUtils.isEmpty(who)) {                dispatchRequestPermissionsResult(requestCode, data);            }startActivityForResult第一个参数就是who,这里的who是REQUEST_PERMISSIONS_WHO_PREFIX,所以不是Null,按照这个逻辑走到了 dispatchRequestPermissionsResult(requestCode, data); 再往里面走

这里写图片描述

这句话的意思是把运行时弹出对话框的所有申请权限的结果保存成数组然后通过我们之前提到的onRequestPermissionsResult来传递。

onRequestPermissionsResult()

这里写图片描述

非常容易理解,其实就是将上面两种情况的权限处理结果回调给当前页面做处理

文章可能繁琐了点,都经过我的实践证明,希望可以帮助大家更加了解内部实现原理

原创粉丝点击