动态权限设置—RxPermissions

首先我们先科普一下它的技术背景:

  • 从 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以下手机的逻辑,现在还在研究中,有知道的大神麻烦告知一下。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352