博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 6.0动态权限申请的处理
阅读量:3741 次
发布时间:2019-05-22

本文共 9742 字,大约阅读时间需要 32 分钟。

1:检查权限:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)              != PackageManager.PERMISSION_GRANTED) {          //申请WRITE_EXTERNAL_STORAGE权限          ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},                  WRITE_EXTERNAL_STORAGE_REQUEST_CODE);      }
2:权限申请后,会弹出dialog供用户选择,在onRequestPermissionResult中做处理

@Override  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {      super.onRequestPermissionsResult(requestCode, permissions, grantResults);    if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {          if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {              // Permission Granted          } else {              // Permission Denied          }      }   }
3:Fragment中使用调用自带函数requestPermisssion 在onrequestpermissionresult中获得结果,fragment嵌套时      用
getParentFragment().requestPermissions方法

@Override  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {      super.onRequestPermissionsResult(requestCode, permissions, grantResults);      List
fragments = getChildFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null) { fragment.onRequestPermissionsResult(requestCode,permissions,grantResults); } } } }
4:封装与框架使用

说完了基本的调用接下来说的是用什么框架解决多个动态权限的问题

封装

此处转载 鸿洋博客

(1)申请权限

虽然权限处理并不复杂,但是需要编写很多重复的代码,所以目前也有很多库对用法进行了封装,大家可以在github首页搜索:android permission,对比了几个库的使用方式,发现这个库据我所见相比较而言使用算是比较简单的,那么就以这个库的源码为基础来讲解,大家有兴趣可以多看几个库的源码。

封装的代码很简单,正如大家的对上面的权限代码所见,没有特别复杂的地方。

对于申请权限的代码,原本的编写为:

if (ContextCompat.checkSelfPermission(this,                Manifest.permission.CALL_PHONE)                != PackageManager.PERMISSION_GRANTED){    ActivityCompat.requestPermissions(this,            new String[]{Manifest.permission.CALL_PHONE},            MY_PERMISSIONS_REQUEST_CALL_PHONE);} else{    callPhone();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

大家可以看到,对于其他的权限,其实申请的逻辑是类似的;唯一不同的肯定就是参数,那么看上面的代码,我们需要3个参数:Activity|Fragment权限字符串数组int型申请码

也就是说,我们只需要写个方法,接受这几个参数即可,然后逻辑是统一的。

public static void needPermission(Fragment fragment, int requestCode, String[] permissions){    requestPermissions(fragment, requestCode, permissions);}@TargetApi(value = Build.VERSION_CODES.M)private static void requestPermissions(Object object, int requestCode, String[] permissions){    if (!Utils.isOverMarshmallow())    {        doExecuteSuccess(object, requestCode);        return;    }    List
deniedPermissions = Utils.findDeniedPermissions(getActivity(object), permissions);
if (deniedPermissions.size() >
0) {
if (object
instanceof Activity) { ((Activity) object).requestPermissions(deniedPermissions.toArray(
new String[deniedPermissions.size()]), requestCode); }
else
if (object
instanceof Fragment) { ((Fragment) object).requestPermissions(deniedPermissions.toArray(
new String[deniedPermissions.size()]), requestCode); }
else {
throw
new IllegalArgumentException(object.getClass().getName() +
" is not supported"); } }
else { doExecuteSuccess(object, requestCode); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Utils.findDeniedPermissions其实就是check没有授权的权限。

#Utils@TargetApi(value = Build.VERSION_CODES.M)public static List
findDeniedPermissions(Activity activity, String... permission){ List
denyPermissions =
new ArrayList<>();
for (String value : permission) {
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED) { denyPermissions.add(value); } }
return denyPermissions;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

那么上述的逻辑就很清晰了,需要的3种参数传入,先去除已经申请的权限,然后开始申请权限。

ok,我相信上面代码,大家扫一眼就可以了解了。

(2)处理权限回调

对于回调,因为要根据是否授权去执行不同的事情,所以很多框架也需要些一连串的代码,或者和前面的申请代码耦合。不过这个框架还是比较方便的,也是我选择它来讲解的原因。

回调主要做的事情:

  1. 了解是否授权成功。
  2. 根据授权情况进行回调。

对于第一条逻辑都一样;对于第二条,因为涉及到两个分支,每个分支执行不同的方法。

对于第二条,很多框架选择将两个分支的方法在申请权限的时候进行注册,然后在回调中根据requestCode进行匹配执行,不过这样需要在针对每次申请进行对象管理。

不过这个框架采取了一种很有意思的做法,它利用注解去确定需要执行的方法,存在两个注解:

@PermissionSuccess(requestCode = 100)@PermissionFail(requestCode = 100)
  • 1
  • 2
  • 1
  • 2

利用反射根据授权情况+requestCode即可找到注解标注的方法,然后直接执行即可。

大致的代码为:

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions,      int[] grantResults) {    PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults);}private static void requestResult(Object obj, int requestCode, String[] permissions,                                  int[] grantResults){    List
deniedPermissions =
new ArrayList<>();
for (
int i =
0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { deniedPermissions.add(permissions[i]); } }
if (deniedPermissions.size() >
0) { doExecuteFail(obj, requestCode); }
else { doExecuteSuccess(obj, requestCode); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

首先根据grantResults进行判断成功还是失败,对于成功则:

private static void doExecuteSuccess(Object activity, int requestCode){    Method executeMethod = Utils.findMethodWithRequestCode(activity.getClass(),            PermissionSuccess.class, requestCode);    executeMethod(activity, executeMethod);}#Utilspublic static  Method findMethodWithRequestCode(Class clazz,  Class annotation, int requestCode){    for (Method method : clazz.getDeclaredMethods())    {        if (method.isAnnotationPresent(annotation))        {            if (isEqualRequestCodeFromAnntation(method, annotation, requestCode))            {                return method;            }        }    }    return null;}

根据注解和requestCode找到方法,然后反射执行即可。失败的逻辑类似,不贴代码了。

ok,到此我们的运行时权限相对于早起版本的变化、特点、以及如何处理和封装都介绍完了。

不过对于上面讲解的库,肯定有人会说:运行时反射会影响效率,没错,不过我已经在上述代码的基础上将运行时注解改成Annotation Processor的方式了,即编译时注解,这样的话,就不存在反射损失效率的问题了。本来准备fork修改,然后PR,结果写完,改动太大,估计PR是不可能通过了,所以另起项目了,也方便后面的做一些扩展和维护。

详见库:.

六、MPermissions用法

对外的接口和PermissionGen基本一致,因为申请只需要三个参数,抛弃了使用原本类库的单例的方式,直接一个几个静态方法,简单整洁暴力。

贴一个用法:

public class MainActivity extends AppCompatActivity{    private Button mBtnSdcard;    private static final int REQUECT_CODE_SDCARD = 2;    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mBtnSdcard = (Button) findViewById(R.id.id_btn_sdcard);        mBtnSdcard.setOnClickListener(new View.OnClickListener()        {            @Override            public void onClick(View v)            {                MPermissions.requestPermissions(MainActivity.this, REQUECT_CODE_SDCARD, Manifest.permission.WRITE_EXTERNAL_STORAGE);            }        });    }    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)    {        MPermissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);        super.onRequestPermissionsResult(requestCode, permissions, grantResults);    }    @PermissionGrant(REQUECT_CODE_SDCARD)    public void requestSdcardSuccess()    {        Toast.makeText(this, "GRANT ACCESS SDCARD!", Toast.LENGTH_SHORT).show();    }    @PermissionDenied(REQUECT_CODE_SDCARD)    public void requestSdcardFailed()    {        Toast.makeText(this, "DENY ACCESS SDCARD!", Toast.LENGTH_SHORT).show();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

是不是简单明了~~对于onRequestPermissionsResult所有的Activity都是一致的,所以可以放到BaseActivity中去。此外,在Fragment中使用的方式一致,详见demo。

详见库:.

至于为什么不直接介绍的源码,因为主要涉及到Annotation Processor,所以以这种方式引出,后面考虑单篇博文介绍下我目前所会的编译时注解的相关做法以及API的使用。

你可能感兴趣的文章
Java数据结构与算法_03 栈 (小型计算器、逆波兰表达式)
查看>>
Java数据结构与算法_04 递归(八皇后问题、迷宫问题)
查看>>
Java数据结构与算法_05 时间复杂度+常用排序算法 (冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、基数排序)
查看>>
Java数据结构与算法_06 查找算法 (顺序查找、二分查找、插值查找、斐波那契查找)
查看>>
Java数据结构与算法_07 哈希表
查看>>
Java数据结构与算法_08 树结构基础部分 (二叉树的遍历、顺序存储二叉树、线索化二叉树)
查看>>
Java数据结构与算法_09 树结构实际应用 (堆排序、哈夫曼树、二叉排序树、平衡二叉树)
查看>>
Java数据结构与算法_10 B树和2-3树的基本介绍
查看>>
Java数据结构与算法_11 图 (深度优先遍历、广度优先遍历)
查看>>
Java数据结构与算法_12 常用算法 (二分查找算法、分治算法-汉诺塔问题、动态规划算法-背包问题、KMP算法-字符串匹配)
查看>>
Java数据结构与算法_13 常用算法(贪心算法-集合覆盖问题、普利姆算法-修路问题、克鲁斯卡尔算法-公交站问题、迪杰斯特拉+弗洛伊德算法-最短路径问题、马踏棋盘算法)
查看>>
①HTML介绍及标签用法
查看>>
②CSS介绍及选择器的基本使用
查看>>
③HTML+CSS 文本格式化 (颜色、单位、文本样式)
查看>>
④HTML+CSS 盒子模型
查看>>
⑤HTML+CSS 浮动
查看>>
⑥HTML+CSS 定位
查看>>
⑦HTML+CSS 设置元素背景
查看>>
⑧HTML+CSS 表格和表单的基本设置
查看>>
⑨HTML+CSS 动画效果(animation)
查看>>