Android6.0执行时权限解析,RxPermissions的使用。自己封装一套权限框架


在Android6.0中,新添加了一个执行时的权限,我相信非常多人都已经知道了。预计也知道怎么用了,这篇博客非常easy。就是告诉大家怎样去申请执行时权限和RxPermission这个权限框架的使用。同一时候依据现有的技术封装思想,去封装一个自己可用的权限框架,好的,我们继续往下看

一.Android M 执行时权限介绍

关于Android M的更新变化,我就不啰嗦了,有兴趣的能够看下Android M更新

而我们的这篇文章,也是直接參考的Google api文档中关于执行时权限这一块的来对应的解说Google API 执行时权限

先来说一些概念性的东西。从 Android 6.0(API 级别 23)開始,用户開始在应用执行时向其授予权限,而不是在应用安装时授予。此方法能够简化应用安装过程。由于用户在安装或更新应用时不须要授予权限。

它还让用户能够对应用的功能进行很多其它控制。这句话的意思就是你安装的时候,Android6.0之前,假设你看到非常多权限,有一两个权限你不想给他,可是假设你不给他,就无法安装,可是像QQ。微信这种应用,是你不想安装就不想安装的吗?这是非常流氓的,而执行时权限出来后,正常安装,可是假设你想使用这个功能。再去申请权限,这就比較合理了。我们接着往下看

系统权限分为两类:正常权限和危急权限:

  • 正常权限不会直接给用户隐私权带来风险。假设您的应用在其清单中列出了正常权限,系统将自己主动授予该权限。

  • 危急权限会授予应用訪问用户机密数据的权限。假设您的应用在其清单中列出了正常权限。系统将自己主动授予该权限。假设您列出了危急权限,则用户必须明白批准您的应用使用这些权限。

这里也比較好理解。危急权限我们须要去申请就OK了,假设你搞不清楚这些权限的差别,这里我推荐你去看正常权限和危急权限 ,在这个表中。列举了全部的权限,你能够依据自己的需求去搜索

我们说了这些概念,事实上我认为你们都会了,那我们直接进入代码环节吧

二.申请权限

权限你能够申请单个,也能够申请多个。我们一步步看,假设我们以打电话的权限为样例。我们在清单文件里填写电话权限

<uses-permission android:name="android.permission.CALL_PHONE"/>

正常来讲,我们仅仅须要调用这段打电话的代码就能够拨打电话了。全部我们写了一个打电话的方法,可是他却报错了,那是由于我们使用的targetSdkVersion是25。大于23。全部他会检查权限,也就是这样

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjY3ODcxMTU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

他警告我们须要去推断权限。那我们就依照他的提示一步步来,首先推断是否允许了该权限

    //正常获取权限
private void checkPermissionForNormal() {
//推断是否允许此权限
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
//假设应用之前请求过此权限但用户拒绝了请求,此方法将返回 true
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CALL_PHONE)) {
Toast.makeText(this, "你之前拒绝过此权限", Toast.LENGTH_SHORT).show();
} else {
//申请权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 100);
}
} else {
callPhone();
}
}

这代码看起来还是比較正常的,首先他会去检查你当前的权限是否等于PackageManager.PERMISSION_GRANTED,0为成功,-1为失败,假设他不等于0,那我就去检查你之前是否请求过该权限,同一时候你点击了拒绝。

注:假设用户在过去拒绝了权限请求。并在权限请求系统对话框中选择了 不再提醒 选项,此方法将返回 false。

假设设备规范禁止应用具有该权限,此方法也会返回 false。

好的,假设都没有,那我就通过ActivityCompat的requestPermissions方法去请求权限,里面的几个參数要注意一下,第一个是上下文,第二个是权限数组。也就是说他支持单个和多个权限的申请,第三个是回调的resultCode,我们来执行一下,看下他是怎样申请的

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjY3ODcxMTU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

好的,那我们如今来处理一下结果吧,实现一下onRequestPermissionsResult方法

   //权限的回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 100: {
//返回的结果数组大于0说明有结果
if (grantResults.length > 0
//由于我们仅仅推断了一个打电话的权限。全部是数组的0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "允许了权限", Toast.LENGTH_SHORT).show();
callPhone();
} else {
Toast.makeText(this, "拒绝了权限", Toast.LENGTH_SHORT).show();
}
return;
}
}
}

这段代码的凝视也非常清楚。我们仅仅要推断有结果,然后就能够去做对应的。处理了,这个是单个的权限

我们再来看下多个权限的申请。首先是申请了

   //正常获取权限
private void checkPermissionForNormal() {
//推断是否允许此权限
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this,
Manifest.permission.SYSTEM_ALERT_WINDOW) != PackageManager.PERMISSION_GRANTED) {
//申请权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA
, Manifest.permission.SYSTEM_ALERT_WINDOW}, 100);
}
}

我在这里申请了一个电话。一个相机的权限。另一个窗体权限。那我们结果的处理怎样呢

    //权限的回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 100: {
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "允许权限", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "拒绝权限", Toast.LENGTH_SHORT).show();
}
}
} else {
Toast.makeText(this, "拒绝了权限", Toast.LENGTH_SHORT).show();
}
return;
}
}
}

相同的我们仅仅须要去推断我们的返回值0或者-1就能够了。那我们来看下终于的演示结果

这里要注意一点的就是你计算申请了执行时权限。你的清单文件里,也还是要加入加入对应的权限

    <uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

三.RxPermissions

RxPermissions是一个封装的权限库,由于使用比較简单,全部我也提出来给大伙讲讲,地址能够參考RxPermissions GitHub

先来说一下这个RxPermissions库的集成工作,由于他是跟着RxJava一起的,假设要使用。还得加入RxJava,并且RxJava有两个版本号,我们这里以RxJava2为样例

加入依赖

    //RxPermissions
compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar'
//RxJava2
compile "io.reactivex.rxjava2:rxjava:2.0.0"

他的使用假设用正常的RxJava语法。那就是这样:

RxPermissions rxPermissions = new RxPermissions(MainActivity.this);
rxPermissions.request(Manifest.permission.CALL_PHONE)
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(Disposable d) { } @Override
public void onNext(Boolean value) {
if(value){
Toast.makeText(MainActivity.this, "允许权限", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "拒绝权限", Toast.LENGTH_SHORT).show();
}
} @Override
public void onError(Throwable e) { } @Override
public void onComplete() { }
});

这样我们能够申请到权限了。如图

当然假设你使用lambda表达式,你会更爽的

RxPermissions rxPermissions = new RxPermissions(MainActivity.this);
rxPermissions
.request(Manifest.permission.CALL_PHONE)
.subscribe(granted -> {
if (granted) {
Toast.makeText(MainActivity.this, "允许权限", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "拒绝权限", Toast.LENGTH_SHORT).show();
}
});

四.权限封装

关于权限的封装事实上还是比較纠结的,我们分析下,首先推断权限,是没有什么问题的,申请权限也是没有什么问题的,可是处理结果就麻烦了。他是在Activity的回调中,事实上在fragment也有这个回调处理。全部如今市面上比較多的就是fragment中处理。而我们上面的RxPermissions也是这样处理的,我们看一下他的源代码

 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;
}

他把这个fragment add在这个activity中,然后再fragment中处理,说实话,挺巧妙的,那我们今天就换一种方式来处理。这就是我们的统配Activity中处理。而我如今教大家另一种封装的方法。那就是实现一个Activity的基类,先看下我们怎样去使用的

checkPermissions(new String[]{Manifest.permission.CALL_PHONE,
Manifest.permission.CAMERA,}, 300, new PermissionsResultListener() {
@Override
public void onSuccessful(int[] grantResults) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "允许权限", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "拒绝权限", Toast.LENGTH_SHORT).show();
}
}
} @Override
public void onFailure() {
Toast.makeText(MainActivity.this, "失败", Toast.LENGTH_SHORT).show();
}
});

能够发现,这里我们就一行代码。checkPermissions调用,里面的參数一个是权限数组,一个是返回码,另一个是回调,那怎样去做呢。事实上就是实现一个接口

public interface PermissionsResultListener {

    //成功
void onSuccessful(int[] grantResults); //失败
void onFailure();
}

以及在PermissionsActivity中完毕它的操作。只是有一个弊端就是须要继承PermissionsActivity。全部我们要写我们的checkPermissions方法,就须要继承这个PermissionsActivity,而这里面的代码说不上难

public class PermissionsActivity extends AppCompatActivity {

    private PermissionsResultListener mListener;
private int mRequestCode;
private List<String> mListPermissions = new ArrayList<>(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
} protected void checkPermissions(String[] permissions, int requestCode, PermissionsResultListener listener) {
//权限不能为空
if (permissions != null || permissions.length != 0) {
mListener = listener;
mRequestCode = requestCode;
for (int i = 0; i < permissions.length; i++) {
if (!isHavePermissions(permissions[i])) {
mListPermissions.add(permissions[i]);
}
}
//遍历完后申请
applyPermissions();
}
} @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == mRequestCode) {
if (grantResults.length > 0) {
mListener.onSuccessful(grantResults);
} else {
mListener.onFailure();
}
}
} //推断权限是否申请
private boolean isHavePermissions(String permissions) {
if (ContextCompat.checkSelfPermission(this, permissions) != PackageManager.PERMISSION_GRANTED) {
return false;
}
return true;
} //申请权限
private void applyPermissions() {
if (!mListPermissions.isEmpty()) {
int size = mListPermissions.size();
ActivityCompat.requestPermissions(this, mListPermissions.toArray(new String[size]), mRequestCode);
}
}
}

这就是我们的权限封装了,到这里你应该明白或者说掌握了执行时权限的绝大部分操作吧,我们执行一下看下

Sample下载

有兴趣的加群讨论:555974449


付费群

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjY3ODcxMTU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

Android6.0执行时权限解析,RxPermissions的使用,自己封装一套权限框架的更多相关文章

  1. Android 6.0 执行时权限处理全然解析

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/50709663: 本文出自:[张鸿洋的博客] 一.概述 随着Android 6. ...

  2. Android6.0运行时权限(基于RxPermission开源库)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 在6.0以前的系统,都是权限一刀切的处理方式,只要用户安装,Manifest申请的权限都会被赋予,并且安装后权限也撤销不了. And ...

  3. Android6.0运行时权限管理

    自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装 ...

  4. Android开发学习之路-Android6.0运行时权限

    在Android6.0以后开始,对于部分敏感的“危险”权限,需要在应用运行时向用户申请,只有用户允许的情况下这个权限才会被授予给应用.这对于用户来说,无疑是一个提升安全性的做法.那么对于开发者,应该怎 ...

  5. Android6.0运行时权限的处理Demo

    MainActivity.java package com.loaderman.permissionsdemo; import android.Manifest; import android.con ...

  6. imx6 Android6.0.1 init.rc解析

    1. 概述 1.1 概述 之前分析过android5的init.rc,不过还是不够仔细,现在来看看android6的,多的就不写了,只写关键点 忘记一些基本概念可以先看看之前的笔记: Android5 ...

  7. 【转】关于使用Android6.0编译程序时,出现getSlotFromBufferLocked: unknown buffer: 0xac0f8650问题的解释

    这个问题是在测试leakCanaryTestDemo时发现的,期初看到有点蒙,这个demo中只使用了一个button和一个textView控件进行测试,按理说是不应该出现这种问题,在 网上查找这个问题 ...

  8. [Erlang危机](5.0)执行时指标

    原创文章.转载请注明出处:server非业余研究http://blog.csdn.net/erlib 作者Sunface .  Then, in times of need, it's also po ...

  9. 【Android】打电话Demo及Android6.0的运行时权限

    新手开局,查看一些旧资料,从打电话.发短信的小应用开始.代码很简单,主要是学习了: 用StartActivity()激活一个Activity组件.这里是激活了系统原生的打电话和发短信Activity. ...

随机推荐

  1. css选择器(第n个类选择器)的坑

    css选择器选择第n个子元素,共有两种写法: .parent span:nth-child(n) 选择parent下的第n个子元素(不管前边是不是span,都算在内) .parent span:nth ...

  2. bzoj 2460 拟阵+判线性相关

    /************************************************************** Problem: 2460 User: idy002 Language: ...

  3. python开发_xml.dom_解析XML文档_完整版_博主推荐

    在阅读之前,你需要了解一些xml.dom的一些理论知识,在这里你可以对xml.dom有一定的了解,如果你阅读完之后. 下面是我做的demo 运行效果: 解析的XML文件位置:c:\\test\\hon ...

  4. Codechef December Challenge 2014 Chef and Apple Trees 水题

    Chef and Apple Trees Chef loves to prepare delicious dishes. This time, Chef has decided to prepare ...

  5. Illegal instruction错误的定位---忽略编译期警告的代价

    在原计算机的linux c++程序可以正确跑起来,但是换了一台机器运行时出现致命错误,程序直接当掉,错误提示如下: Illegal instruction (core dumped) 造成改错的主要原 ...

  6. java并发基础(一)

    最近在看<java并发编程实战>,希望自己有毅力把它读完. 线程本身有很多优势,比如可以发挥多处理器的强大能力.建模更加简单.简化异步事件的处理.使用户界面的相应更加灵敏,但是更多的需要程 ...

  7. windows命令行快捷操作

    net use \\ip\ipc$ " " /user:" " 建立IPC空链接 net use \\ip\ipc$ "密码" /user: ...

  8. 连接本地websocket服务延迟的问题

    今天用C#编写了一个Chrome Remote Debugger的客户端程序,发现使用rest和websocket程序时第一次连接的时候特别慢,大概每次都要消耗一秒左右,而用chrome直接连接却没有 ...

  9. asp.net MVC 3/4 equivalent to a response.filter

    am in a need to intercept all of the html that will be sent to the browser and replace some tags tha ...

  10. MVC扩展控制器, 把部分视图转换成字符串(带验证信息), 并以json传递给前端视图

    当我们使用jQuery异步提交表单数据的时候,需要把部分视图转换成字符串(带验证信息),以json的形式传递给前端视图.   使用jQuery异步加载部分视图,返回内容追加到页面某个div:   jQ ...