基本概念大家都知道
我就一笔带过了
Android 6.0是Android发展史上的一个分水岭,从这个版本开始无论是系统流畅度、运行速度、安全性、用户隐私保护、用户控制、动态授权等都得到了质的提升。
其中隐私保护就体现在动态权限获取上,也是从这个版本开始需要进行动态的用户权限获取
既然说到权限获取,那就需要先知道为什么要获取权限
google 将一些权限等级提升,归为危险权限,将这些权限是否授权给App的选择权交给用户
危险权限列表,这里不列出,也不一定想看这些列表,请自行搜索
动态权限申请涉及到四个系统方法的使用
我们以WRITE_EXTERNAL_STORAGE为例
// 判断当前权限是否曾经授权过
1:ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)
// 请求权限
2:ActivityCompat.requestPermissions(SplashActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE)
// 权限结果回调
3:onRequestPermissionsResult()
// ??????这是个啥?我敢保证你不知道,如果你知道就不会看到我这篇博客了(是否需要解释我为什么需要这个权限)
4:ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
开始进行动态权限申请
第一步:在清单文件中配置相关权限
一定要声明相关权限,不然不管如何申请系统都不会弹出权限弹窗的
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
然后就要在App启动时或者需要权限的地方进行权限申请了
因为权限是只需要授权一次之后,就不需要多次请求了,所以说理想状态下,一个App在一个手机中的一生,只会进行一次权限申请,如果是已经授权过的还要重复申请显然是有点浪费
所以我们在进行权限申请之前,先判断当前权限是否需要申请,也就是说是否已经授权过了
// 判断权限是否需要申请
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 需要进行权限申请
} else {
// 不需要进行权限申请或者所有权限都已授权
}
需要注意的有两点
有权限则会返回常量 PackageManager.PERMISSION_GRANTED,他的值是0;没有权限则返回 PackageManager.PERMISSION_DENIED,他的值为 -1;
这里传进去的是一个常量PackageManager.PERMISSION_DENIED,
他对应的值是
public static final String WRITE_EXTERNAL_STORAGE="android.permission.WRITE_EXTERNAL_STORAGE";
当然,我们可以将这个字符串手写传进去,但注意:如果值不对是无法弹出权限申请窗的。所以说既然android系统提供了这个常量,那我们为什么不使用呢?
如果不需要申请权限则正常执行业务流程就OK
我们要说的是需要申请权限的情况
一般国内的做法是直接进行权限申请了,很霸道,用户压根不知道你为什么要这么多权限,给一个还要,给一个还要,给着给着心里就开始发毛了
官方建议的做法通常是先弹出一个自己的弹窗,告诉用户我需要哪些权限以及拿这些权限的原因和目的,让用户有足够的心理准备,用户点击知道后,就可以开始进行权限申请了
我们继续说用户点击知道后的操作
我们调用这个方法来进行权限申请:
ActivityCompat.requestPermissions(SplashActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_REQUEST_CODE)
注意:String数组的的权限是一次性可以放进去一组的,不需要分开来重复调用此方法
调用完此方法之后,系统会自动弹出权限申请弹窗像用户索取权限,在权限申请回调中我们能监听到用户是否授予了我们权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 判断是否是我们刚刚发起的权限申请
switch (requestCode) {
case PERMISSIONS_REQUEST_CODE:
// 判断是否是已经授权过
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 执行授权后的操作
} else {
// 执行未授权的操作
// 判断是否曾经拒绝并且勾选了不再提醒(我应该向用户解释一下我为什么要这些权限吗)
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// 弹出解释框
} else {
// 跳转到系统权限设置页面
}
}
break;
default:
break
}
}
好我们来看一下回调里的这一堆判断
首先判断一下请求码是不是我们刚刚发起的请求
然后判断是否已经授权过当前权限,其实如果你在权限申请之前做的够好的话是永远不会走到这个判断里面来的,有权限了为什么还要申请让系统告诉你你有权限了呢,直接自己判断不就好了,还省效率,按照我们上面的判断就可以实现了
然后我们重点讲一下未授权的时候的操作
我们先调用ActivityCompat.shouldShowRequestPermissionRationale
我们先来翻译一下,大白话就是:我应该向用户解释一下我为什么要这些权限吗?
假如说你是android系统,一个App问你需不需要解释,那你会在什么时候告诉他需要,什么时候告诉他不需要呢?
我们来分不同的场景来分析一下
1:App第一次安装打开,android认为是不需要解释的,所以这个时候返回的是false,这时候有人要说了,你上面不是说要加提醒告诉你要申请什么权限让他们心里有数吗?是的,但是注意那是说明,不是解释,说明弹窗和解释弹窗的目的是不一样的,所以说内容也不一样,当然你也可以写成一样的
2:从来都没有展示给用户权限申请的弹窗,android认为是不需要解释的,因为用户都没有看到权限申请,说不定就同意了呢,为什么要解释呢?这个其实和第一种是同一个情况
3:用户点击了拒绝,然后再次进行权限申请前,android认为是需要解释的,因为android认为用户拒绝了,你有必要解释一下了
4:用户点击了拒绝,并且勾选了不再提醒,android认为是不需要解释的,因为解释也没有卵用了,系统是再也不会拉起权限弹窗询问用户了,那你还解释个毛
总结一下:只要第3种情况是需要解释的,其他的情况都不需要解释
所以说ActivityCompat.shouldShowRequestPermissionRationale真正用法是在回调中配合需要申请权限的时候使用的,有人在没调用权限申请之前就询问系统,所以说永远返回的是false
所以说ActivityCompat.shouldShowRequestPermissionRationale的作用也是可以判断是否勾选了不再提醒,如果没勾选就解释,勾选了就跳转到系统设置页面
有时间录制一个gif图展示给大家