为什么要进行权限申请?
Android 6.0 ( API23 MarshMallow 棉花糖):运行时权限
-
在6.0之前,应用安装时,会提示APP所需要的权限列表,同意之后安装,该app就被赋予所有的权限。
-
在6.0之后,google对权限进行了分类,普通权限和危险权限。无论是普通权限还是危险权限都需要在AndroidManifest中进行声明。普通权限在应用安装时就会被授予;而危险权限需要在应用安装之后进行动态申请,由用户进行管控。总共有9组危险权限,对于同一组内的危险权限,只要申请一个就行了,申请一个就相当于全家桶(全组许可)。
系统提供的权限申请方式
申请单个相机权限:ContextCompat 、ActivityCompat 、
//设置requestCode
private val PERMISSION_REQUEST_CAMERA = 1
//判断是否已经授予相机权限,没有则进行申请; 否则do something you wanted
private fun requestPermissionNormal() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
//没有授予权限
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA),
PERMISSION_REQUEST_CAMERA)
} else {
//todo something you wanted
}
}
//申请权限结果的回调 activity 和 fragment都有这个方法
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<outString>, grantResults: IntArray) {
if (requestCode == PERMISSION_REQUEST_CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//todo something you wanted
} else {
// Permission Denied
}
return
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
RxPermissions的实现方式
github地址 https://github.com/tbruyelle/RxPermissions
推荐在onCreate中使用
依赖引入:
project 的 build.gradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
module 的 build.gradle
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
单个权限申请
val rxPermission = RxPermissions(this@MainActivity)
rxPermission.request(Manifest.permission.CAMERA)
.subscribe(Consumer<Boolean> { granted ->
if (granted) {
Log.d(MyApplication.TAG, " is granted.")
} else {
Log.d(MyApplication.TAG, " is denied.")
}
})
多个权限申请
val rxPermission = RxPermissions(this@MainActivity)
rxPermission.requestEach(Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_CALENDAR,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_PHONE_STATE)
.subscribe(Consumer<Permission> { permission ->
if (permission.granted) {
// 用户已经同意该权限
Log.d(MyApplication.TAG, permission.name + " is granted.")
} else if (permission.shouldShowRequestPermissionRationale) {
// 用户拒绝了该权限,没有选中『不再询问』(Never ask again),那么下次再次启动时,还会提示请求权限的对话框
Log.d(MyApplication.TAG, permission.name + " is denied. More info should be provided.")
} else {
// 用户拒绝了该权限,并且选中『不再询问』
Log.d(MyApplication.TAG, permission.name + " is denied.")
}
})
那么RxPermissions是如何实现的呢?下面我们进入源码分析。
RxPermissions 就包含4个类,真正有用的是Permission/ RxPermissions/ RxPermissionsFragment
源码分析
创建RxPermissions的实例
- 根据TAG找rxPermissionFragment,为空的话就new 一个rxPermissionFragment,并添加进来。
- RxPermissionFragment 没有加载布局(用户无感知),在fragment中进行权限的申请和结果反馈。
RxPermissions.java
public RxPermissions(FragmentActivity activity) {
this.mRxPermissionsFragment = this.getLazySingleton(activity.getSupportFragmentManager());
}
//支持在activity/fragment中使用
public RxPermissions(Fragment fragment) {
this.mRxPermissionsFragment = this.getLazySingleton(fragment.getChildFragmentManager());
}
//单例,懒加载的方式返回一个RxPermissionFragment
private RxPermissions.Lazy<RxPermissionsFragment> getLazySingleton(final FragmentManager fragmentManager) {
return new RxPermissions.Lazy<RxPermissionsFragment>() {
private RxPermissionsFragment rxPermissionsFragment;
public synchronized RxPermissionsFragment get() {
if (this.rxPermissionsFragment == null) {
this.rxPermissionsFragment = RxPermissions.this.getRxPermissionsFragment(fragmentManager);
}
return this.rxPermissionsFragment;
}
};
}
//fragmentManager添加进来
private RxPermissionsFragment getRxPermissionsFragment(FragmentManager fragmentManager) {
RxPermissionsFragment rxPermissionsFragment = this.findRxPermissionsFragment(fragmentManager);
boolean isNewInstance = rxPermissionsFragment == null;
if (isNewInstance) {
rxPermissionsFragment = new RxPermissionsFragment();
fragmentManager.beginTransaction().add(rxPermissionsFragment, TAG).commitNow();
}
return rxPermissionsFragment;
}
//只加载一个fragment
private RxPermissionsFragment findRxPermissionsFragment(FragmentManager fragmentManager) {
return (RxPermissionsFragment)fragmentManager.findFragmentByTag(TAG);
}
在fragment中进行权限的申请和结果反馈。
其它的就是RxJava的各种操作符了。
- request() 请求权限列表,需要等所有权限请求都执行完后,才返回true/false,只要有一个失败,就返回false
- requestEach(),分两部分返回,已经授权的先返回;没有授权的,等待所有权限请求都执行完后,才返回。每一个申请的权限,都有一个Permission类(name、granted、shouldShowRequestPermissionRationale(字段为false,即用户点击了禁止后不再询问,且拒绝了权限授予,以后不会再弹框))
需要在AndroidManifest.xml中,声明这些permission,否则就直接拒绝了,无法弹框处理