首先我们先科普一下它的技术背景:
-
从 Android 6.0(API 级别 23)开始,出于对用户安全性能的考虑,将权限这部分分成 了两类:一类是Install权限,称之为安装时权限,另一类是Runtime权限,称之为运行时权限。
-
安装时权限,就是在安装app时赋予该app的权限。比如:Normal和Signature级别的权限都是安装时权限。赋予app Normal和Signature权限时,不会给用户提示界面,系统自动决定权限的赋予。
这里需要注意一点,对于Signature权限,如果使用权限的app与声明权限的app的签名不一致,则系统拒绝赋予该Signature权限。这句话怎么理解呢?
声明权限是指在AndroidManifest.xml中使用<permission>标签的权限
使用权限是指在AndroidManifest.xml中使用<uses-permission>标签的权限。
举个场景例子:
app A中声明了权限PermissionA,app B中想要使用权限PermissionA。
那么app B在清单文件中配置了PermissionA。如果这个PermissionA的protectionLevel(风险级别)属性设置为Normal,那么app B完全可以获得PermissionA使用,但如果PermissionA的protectionLevel属性设置为Signature,因为app A 与app B签名文件不一样,那么app B不会获得PermissionA的使用
还不怎么理解的同学给你们两个网页,结合着看,受益挺多
Android声明和使用权限 、Android 权限的一些细节
- 运行时权限,是指在app运行过程中,赋予app的权限。这个过程中,会显示明显的权限授予界面,让用户决定是否授予权限。比如:Dangerous级别的权限,如果运行在Android 6.0及以上的手机系统中,app在运行时必须主动申请这些Dangerous权限,否则app就不会获取到dangerous权限。
注意一点,这种权限有点特殊,和上面的分类不同,它的分类具体来说和app有关系:如果app的targetSdkVersion是22及以下,Dangerous权限归到安装时权限,如果app的targetSdkVersion是23及以上Dangerous权限归到运行时权限
说到这里了,总结一下共说了几种权限:
- Normal: 低风险的,不会对系统、用户或其他应用程序造成危害,这类权限不涉及个人隐私,不需要用户进行授权,比如手机震动,访问网络。
- Dangerous 高风险的,系统将可能要求用户输入相关信息,才会授予此权限,这类权限涉及个人隐私,需要用户进行授权,比如读取SD卡,访问通讯录等。
- Signature 只有当应用程序所用数字签名与声明此权限的应用程序所用数字签名相同时,才能将权限授给它。
- SignatureOrSystem 将权限授给具有相同数字签名的应用程序或Android包类,这一级别适用于非常特殊的情况,比如多个供应商需要通过系统影像共享功能时(简单了解即可,几乎用不到)
RxPermissions的好处
- 开发者不用担心Android运行环境的版本,如果系统是Android 6.0之前的版本,RxPermissions返回的结果是true,即app请求的每个权限都被允许
RxPermissions内部已经对Android版本进行了判断:
boolean isMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
public boolean isGranted(String permission) {
// 如果是Android 6.0 (Api 23)之前,则权限被允许使用。
return !isMarshmallow() || mRxPermissionsFragment.isGranted(permission);
}
- 将权限申请的代码和请求结果的代码放在一起管理,避免了代码的分散。
权限的申请原来在requestPermissions()方法中,请求的结果放在onRequestPermissionsResult()方法中。
而RxPermissions通过request(需要的权限)与subscribe(Action)统一进行管理操作
- RxPermissions具备Rx(RxJava)的特性,例如可以使用链式操作,可以执行filter操作、transform操作、lambda表达式等等。
RxPermissions获取运行时权限的步骤
- 准备工作
⑴ 安卓手机必须是Android 6.0 (API level >= 23)以上,因为6.0以下安卓手机没有运行时权限这个概念
⑵ 使用这个库的时候,项目文件build.gradle中的targetSdkVersion >= 23
⑶ 使用这个库的时候,项目文件build.gradle中的minSdkVersion >= 11 - 添加依赖
因为要用到RxPermissions,所以先加入依赖,而RxPermissions又属于RX系列,所以也要加入对rxjava的依赖
compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'
compile 'io.reactivex:rxjava:1.1.3'
- 添加权限
在AndroidManifest.xml加入项目所需的运行时权限,例如:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
- Activity代码操作
细分的化可以分成三种操作:
①.请求单个权限
//场景模拟是点击button,用RxPermissions申请读取日程提醒权限
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
RxPermissions.getInstance(TestActivity.this)
.request(Manifest.permission.READ_CALENDAR)//这里填写所需要的权限
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
if (aBoolean) {//true表示获取权限成功(如果手机为android6.0以下的话这里总是返回true,不会弹框权限提示)
Log.i("permissions", Manifest.permission.READ_CALENDAR + ":获取成功");
} else {
Log.i("permissions", Manifest.permission.READ_CALENDAR + ":获取失败");
}
}
});
}
});
效果图如下:
Activity界面
点击开启日程权限按钮
②.一次申请多个权限
RxPermissions.getInstance(TestActivity.this)
.request(Manifest.permission.RECEIVE_MMS, Manifest.permission.READ_CALL_LOG)//多个权限用","隔开
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
if (aBoolean) {
//当所有权限都允许之后,返回true
Log.i("permissions", "btn_more_sametime:" + aBoolean);
} else {
//只要有一个权限禁止,返回false,下一次申请只申请没通过申请的权限
Log.i("permissions", "btn_more_sametime:" + aBoolean);
}
}
});
效果图如下:
Activity界面 点击开启彩信和通话记录权限按钮 点击开启彩信和通话记录权限按钮
③.分别申请多个权限
//分别申请多个权限时,使用requestEach
RxPermissions.getInstance(TestActivity.this)
.requestEach(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
.subscribe(new Action1<Permission>() {
@Override
public void call(Permission permission) {
if (permission.name.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
//当ACCESS_FINE_LOCATION权限获取成功时,permission.granted=true
Log.i("permissions", Manifest.permission.ACCESS_FINE_LOCATION + ":" + permission.granted);
}
if (permission.name.equals(Manifest.permission.RECORD_AUDIO)) {
//当RECORD_AUDIO 权限获取成功时,permission.granted=true
Log.i("permissions", Manifest.permission.RECORD_AUDIO + ":" + permission.granted);
}
if (permission.name.equals(Manifest.permission.CAMERA)) {
//当CAMERA权限获取成功时,permission.granted=true
Log.i("permissions", Manifest.permission.CAMERA + ":" + permission.granted);
}
}
});
效果图如下:
Activity界面 点击开启定位+视频+相机权限按钮 点击开启定位+视频+相机权限按钮 点击开启定位+视频+相机权限按钮
注意
⑴由于在请求权限的过程中app有可能会被重启,所以权限请求必须放在初始化的阶段,比如在Activity.onCreate/onResume, 或者
View.onFinishInflate方法中。如果不这样处理,那么如果app在请求过程中重启的话,权限请求结果将不会发送给订阅者即subscriber。
⑵上图可知多次权限申请的两种方式效果图完全一样,都是一项项弹出,一项项让用户选择。它俩的区别“同时”和“分别”是体现在代码结果的获取上的.“同时”是等用户把每项权限弹框都选择完后执行结果回调,所有的权限统一处理,只要有一项不允许,就走false,“分别”也是等用户把每项权限弹框都选择完后执行结果回调,但所有的权限不统一处理,每项权限都有一个结果回调处理方法。这块不要弄混
⑶权限的弹框样式不同的手机不同的效果图,这些Dialog是各个手机厂商定制的,不能由开发者定制。
关键部分就这些了,挺简单的。动态权限授权虽然给程序员带来了一些麻烦, 但是对用户的安全性来讲还是很有必要的, 我们也应该欢迎, 毕竟每个程序员都是半个产品经理。
在开发过程中遇到一个问题,就是在vivo(垃圾! 胡改八改!)X9 (6.0.1 API 23)手机上运行程序,测试出的结果是6.0以下手机的逻辑,现在还在研究中,有知道的大神麻烦告知一下。
网友评论