为什么需要申请动态权限
android在6.0之前申请权限是在manifest中配置的,但在6.0版本了保护用户隐私引入了一种新的权限模式,这种模式权限分为两种:
-
非敏感权限:这种权限是不需要动态申请,只需要在manifest中配置,和6.0之前请求权限是一样的。
-
敏感权限:在用户需要使用一些敏感权限需要向系统动态申请,这种权限是分组的,一组权限只要申请了其中的一个,同组的其他权限也就被申请了。
特殊权限组(来自Google文档)
Permission Group Permissions CALENDAR
READ_CALENDAR``WRITE_CALENDAR
CALL_LOG
READ_CALL_LOG
WRITE_CALL_LOG``PROCESS_OUTGOING_CALLS
CAMERA
CAMERA
CONTACTS
READ_CONTACTS``WRITE_CONTACTS``GET_ACCOUNTS
LOCATION
ACCESS_FINE_LOCATION``ACCESS_COARSE_LOCATION
MICROPHONE
RECORD_AUDIO
PHONE
READ_PHONE_STATE``READ_PHONE_NUMBERS``CALL_PHONE``ANSWER_PHONE_CALLS``ADD_VOICEMAIL``USE_SIP
SENSORS
BODY_SENSORS
SMS
SEND_SMS``RECEIVE_SMS``READ_SMS``RECEIVE_WAP_PUSH``RECEIVE_MMS
STORAGE
READ_EXTERNAL_STORAGE``WRITE_EXTERNAL_STORAGE
原生申请权限方式
-
检查系统是否有该权限,没有则调用
requestPermissions
方法if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, Manifest.permission.CAMERA,10) }
-
重写onRequestPermissionsResult,判断是否申请成功
if (requestCode == 10) { if (TextUtils.equals(permissions[0],Manifest.permission.WRITE_EXTERNAL_STORAGE) && grantResults[0] == PackageManager.PERMISSION_DENIED) { //用户不同意,向用户展示该权限作用 if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { alertDialog( "请注意", "本应用需要使用访问本地存储权限,否则无法正常使用!", false, "确定", "取消", DialogInterface.OnClickListener { _, _ -> finish() }, DialogInterface.OnClickListener { _, _ -> finish() }) return } } }
RxPermissions申请权限方式
-
单个权限的申请
RxPermissions(this).request(Manifest.permission.ACCESS_COARSE_LOCATION) .subscribe { if (it) { //申请成功 } else { //申请被拒 } }
-
多个权限的申请
RxPermissions(this).requestEach( Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS ) .subscribe { permission -> when { permission.granted -> { //申请成功 } permission.shouldShowRequestPermissionRationale -> { // 用户拒绝了该权限,没有选择 不再提示 ,下次请求时,还会提示请求权限的对话框 } else -> { // 用户拒绝了该权限,选择了 不再提示 ,再次请求不会询问,需要在setting中开启 } } }
为什么RxPermissions权限请求相比系统的权限请求简洁了许多,其实框架内部帮我们实现了那些复杂的操作,接下来我们看一下RxPermissions内部是怎么实现的。
源码浅析
RxPermissions主要的是包含3个类,分别是Permission
、RxPermissions
、RxPermissionsFragment
。
首先我们先看构造方法,该方法只有一行代码,获取Fragment
public RxPermissions(@NonNull Activity activity) {
mRxPermissionsFragment = getRxPermissionsFragment(activity);
}
getRxPermissionsFragment方法里,根据TAG找rxPermissionFragment
,为空的话就创建一个rxPermissionFragment
然后添加到Activity中,权限的请求及回调都在这个Fragment中完成,具体下面会讲。
private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
boolean isNewInstance = rxPermissionsFragment == null;
if (isNewInstance) {
rxPermissionsFragment = new RxPermissionsFragment();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager
.beginTransaction()
.add(rxPermissionsFragment, TAG)
.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
return rxPermissionsFragment;
}
private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
//根据TAG找到fragment
return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
}
接下来调用方法request
,ensure
,requestImplementation
public Observable<Boolean> request(final String... permissions) {
return Observable.just(TRIGGER).compose(ensure(permissions));
}
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
// 将Observable<Permission>转换为Observable<Boolean>
return new ObservableTransformer<T, Boolean>() {
@Override
public ObservableSource<Boolean> apply(Observable<T> o) {
return request(o, permissions)
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(List<Permission> permissions) throws Exception {
//如果permissions为空,直接返回Observable.empty(),不执行下面的逻辑
if (permissions.isEmpty()) {
return Observable.empty();
}
//遍历permissions,如果有一个Permission被拒,则返回false并发送出去
for (Permission p : permissions) {
if (!p.granted) {
return Observable.just(false);
}
}
//如果权限都申请成功,则发送true
return Observable.just(true);
}
});
}
};
}
private Observable<Permission> requestImplementation(final String... permissions) {
List<Observable<Permission>> list = new ArrayList<>(permissions.length);
List<String> unrequestedPermissions = new ArrayList<>();
//遍历permissions,在mRxPermissionsFragment中判断该权限是否已经请求成功,如果成功构建成Permission通过Observable.just()发送出去并将Observable添加到list中
for (String permission : permissions) {
mRxPermissionsFragment.log("Requesting permission " + permission);
if (isGranted(permission)) {
list.add(Observable.just(new Permission(permission, true, false)));
continue;
}
// 如果权限被拒绝
if (isRevoked(permission)) {
list.add(Observable.just(new Permission(permission, false, false)));
continue;
}
//如果权限还没有申请过,则创建一个PublishSubject并添加到 unrequestedPermissions中
PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
if (subject == null) {
unrequestedPermissions.add(permission);
subject = PublishSubject.create();
mRxPermissionsFragment.setSubjectForPermission(permission, subject);
}
list.add(subject);
}
if (!unrequestedPermissions.isEmpty()) {
String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
//调用requestPermissionsFromFragment中的方法申请权限
requestPermissionsFromFragment(unrequestedPermissionsArray);
}
//将多个Observable结合成一个Observable发射出去
return Observable.concat(Observable.fromIterable(list));
}
这里最重要的方法在RxPermissionsFragment
这个类中,包括权限的请求、数据回调
void requestPermissions(@NonNull String[] permissions) {
//调用系统的请求权限的方法
requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);
}
void onRequestPermissionsResult(String permissions[], int[] grantResults, boolean[] shouldShowRequestPermissionRationale) {
for (int i = 0, size = permissions.length; i < size; i++) {
PublishSubject<Permission> subject = mSubjects.get(permissions[i]);
...
boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
//将结果封装成Permission发送出去
subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
}
}
到这里我们已经分析完整个request
的流程,还剩下requestEach
没分析,其实requestEach
的流程与上面相似,这里就不作分析了。从整体上来看RxPermissions的流程很简单,但是这里面用到了很多RxJava
的操作符,通过监听者模式得到请求结果并发送出去。
总结
- 创建一个空的Fragment添加到Activity中
- 遍历权限列表,没有请求过权限则通过Fragment调用请求权限的方法
- 在Fragment中重写
onRequestPermissionsResult
方法,并将结果发送出去 - 合并Observable数据流