Android 动态权限管理
最新
Android 6.0(Marshmallow, 软棉花糖,Api 23),权限分为普通权限和许可权限,许可权限分类归组,该组一个权限被许可后,其他的权限均可使用。
基本介绍
普通权限
只需在xml申请即可,使用方法和6.0之前的一样。应用安装后会默认获得许可。
许可权限
具体权限分组情况可以使用以下shell命令查看
1
adb shell pm list permissions -d -g
同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了
相关方法
ContextCompat.checkSelfPermission()
检查应用是否拥有该权限,若已授权,返回值为PERMISSION_GRANTED,否则返回PERMISSION_DENIED。
ActivityCompat.requestPermissions()
该方法在M之前版本调用,OnRequestPermissionsResultCallback 直接被调用,带着正确的 PERMISSION_GRANTED或者 PERMISSION_DENIED。
AppCompatActivity.onRequestPermissionsResult()
该方法类似于Activity的OnActivityResult()的回调方法,主要接收请求授权的返回值。
需运行时动态申请的权限组
日历
android.permission-group.CALENDAR
相机
android.permission-group.CAMERA
联系人
android.permission-group.CONTACTS
定位
android.permission-group.LOCATION
耳机
android.permission-group.MICROPHONE
电话
android.permission-group.PHONE
传感器
android.permission-group.SENSORS
短信
android.permission-group.SMS
存储
android.permission-group.STORAGE
权限适配解决方案
基本方案(原生方法)
原生方案就是采用android系统提供的权限相关的方法来动态的做权限适配处理,是其他解决方案的基础
我这里来测试读取联系人和打电话这两个6.0之后要在运行时赋予的权限。
MainActivity.java文件内容如下:
1 | package com.rainmonth.myapplication; |
activity_main.xml文件如下
1 |
|
权限申请结果的处理主要在onRequestPermissionsResult中,而处理权限申请所用到的两个HashMap则是在requestPermissions就传递过去了。根据requestCode来在map中查找对应的Runnable对象来处理。
RxJava + RxPermissions方案
在了解了RxJava后,若果你看到上述代码就会觉得上面的基本方案肯定能有一种RxJava式的封装来解决(基本方案中其处理核心就是利用系统提供的onRequestPermissionsResult这个回调方法,RxJava可以很好的解决回调问题),没错,RxPermissions就应运而生了。
RxPermissions的源码还没时间具体分析,先看看它的使用方式。
引入
添加依赖
1
2
3
4
5
6
7
8
9// RxJava 版本小于2.0
dependencies {
compile 'com.tbruyelle.rxpermissions:rxpermissions:0.9.0@aar'
}
// RxJava 版本2.0以上
dependencies {
compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.8.2@aar'
}直接申请权限(以Manifest.permission.CAMERA为例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15RxPermissions.getInstance(this)
.request(Manifest.permission.CAMERA)
.subscribe(new Action1<Boolean>() {
public void call(Boolean granted) {
if (granted) { // 在android 6.0之前会默认返回true
// 已经获取权限
String jpgPath = getCacheDir() + "test.jpg";
takePhotoByPath(jpgPath, 2);
} else {
// 未获取权限
Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
}
}
});条件触发获取权限(可以结合RxBinding使用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16RxView.clicks(findViewById(R.id.request_permission))
.compose(RxPermissions.getInstance(this).ensure(Manifest.permission.CAMERA))
.subscribe(new Action1<Boolean>() {
public void call(Boolean granted) {
if (granted) { // 在android 6.0之前会默认返回true
// 已经获取权限
String jpgPath = getCacheDir() + "test.jpg";
takePhotoByPath(jpgPath, 2);
} else {
// 未获取权限
Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
}
}
});同时请求多个权限(合并结果)
以同时申请拍照和录音权限,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14RxPermissions.getInstance(MainActivity.this).request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
.subscribe(new Action1<Boolean>() {
public void call(Boolean granted) {
if (granted) { // 在android 6.0之前会默认返回true
// 已经获取权限
String jpgPath = getCacheDir() + "test.jpg";
takePhotoByPath(jpgPath, 2);
} else {
// 未获取权限
Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
}
}
});上面这种请求权限方式,只有所有的权限请求都同意之后,才会返回true,有一个为false,则返回false
同时获取多个权限(分别获取结果)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19RxPermissions.getInstance(MainActivity.this).requestEach(Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO)
.subscribe(new Action1<Permission>() {
public void call(Permission permission) {
if (permission.name.equals(Manifest.permission.CAMERA)) {
if (permission.granted) {
String jpgPath = getCacheDir() + "test.jpg";
takePhotoByPath(jpgPath, 2);
} else {
// 未获取权限
Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
}
} else if (permission.name.equals(Manifest.permission.RECORD_AUDIO)) {
}
}
});
RxJava的这种链式写法很好的应用在权限请求上了,哈哈!
其他问题
- 在部分手机Android 5.0上直接使用ContextWrapper的checkSelfPermission方法会抛出异常(NoSuchMethodException)这个时候记得将其替换成ContextCompat的checkSelfPermission方法
- API 23之前的机子调用checkSelfPermission的返回值一直是0,也就是PERMISSION.GRANTED(不管用户是否已经赋予该权限),解决方法就是调用support包下面的PermissionChecker的checkSelfPermission方法
其他与权限申请相关的项目
使用标注的方式,动态生成类处理运行时权限,目前还不支持嵌套Fragment。
简化运行时权限处理
Google官方的例子