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(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转换为Observable
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
的操作符,通过监听者模式得到请求结果并发送出去。
onRequestPermissionsResult
方法,并将结果发送出去