Android 6.0 运行时权限封装框架

作者: 红橙Darren | 来源:发表于2017-01-17 09:16 被阅读2059次

    1.概述


    视频讲解都已经录了好几天,但是最近实在抽不开身一直在忙Unity3D,就连光棍节都在写,上次我们只是写了Android 6.0 运行时权限处理解析,但是并未对其做代码封装,这一次我们做一个彻底的处理。
      附视频讲解地址:http://pan.baidu.com/s/1bpqqkGn
      

    这里写图片描述

    2.框架封装


    2.1. 简单例子

    public class MainActivity extends AppCompatActivity {
        // 打电话权限申请的请求码
        private static final int CALL_PHONE_REQUEST_CODE = 0x0011;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void phoneClick(View view){
            if(ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
                    != PackageManager.PERMISSION_GRANTED){
                Toast.makeText(this, "申请权限", Toast.LENGTH_SHORT).show();
                ActivityCompat.requestPermissions(this,
                        new String[]{"Manifest.permission.CALL_PHONE"}, CALL_PHONE_REQUEST_CODE);
            }else {
                callPhone();
            }
        }
    
        /**
        * 拨打电话
        **/
        private void callPhone() {
            Intent intent = new Intent(Intent.ACTION_CALL);
            Uri data = Uri.parse("tel:147****2514");
            intent.setData(data);
            startActivity(intent);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if(requestCode == CALL_PHONE_REQUEST_CODE){
                if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // Permission Granted
                    callPhone();
                } else {
                    // Permission Denied
                    Toast.makeText(this,"权限被拒绝了",Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

    这是从上一篇中复制过来的,并没有做过任何处理,如果每次申请权限的地方都需要这么做,那就比较麻烦了,那么我们肯定要对phoneClick()和onRequestPermissionsResult()里面的代码进行处理,那么要处理成什么样子?当然是所有的代码都可以优化成一行,别人都这么说的。

    2.1. 确定方式
      到底采用什么方式去封装,这个github上面有很多,中国人,日本人,韩国人各国人民都有,这个不是开完笑的真的都有,这里我才用反射+注解的方式去实现。
      
      2.2. 参数传递和传递方式
      我们肯定要新建类,至于传什么参数? 第一个参数反射的类this,第二个参数请求码用于监听反馈处理,第三个参数传请求权限的数组
      利用什么方式传递过去那么?可以在工具类里面写一个静态的方法一把塞过去。但是在这里我们可以使用链式调用这种方式我们也经常使用,比如Okhttp,Gilde,甚至是Android的AlertDialog都是使用的这个方式,可以装装B

    public class PermissionHelper {
        // 1. 传什么参数
        // 1.1. Object Fragment or Activity  1.2. int 请求码   1.3.需要请求的权限  string[]
        private Object mObject;
        private int mRequestCode;
        private String[] mRequestPermission;
    
        private PermissionHelper(Object object){
            this.mObject = object;
        }
    
        // 2.已什么的方式传参数
        // 2.1 直接传参数
        public static void  requestPermission(Activity activity,int requestCode,String[] permissions){
                PermissionHelper.with(activity).requestCode(requestCode).
                        requestPermission(permissions).request();
        }
    
        public static void  requestPermission(Fragment fragment,int requestCode,String[] permissions){
            PermissionHelper.with(fragment).requestCode(requestCode).
                    requestPermission(permissions).request();
        }
    
        // 2.2 链式的方式传
        // 传Activity
        public static PermissionHelper with(Activity activity){
            return new PermissionHelper(activity);
        }
    
        // 传Fragment
        public static PermissionHelper with(Fragment fragment){
            return new PermissionHelper(fragment);
        }
    
        // 添加一个请求码
        public PermissionHelper requestCode(int requestCode){
            this.mRequestCode = requestCode;
            return this;
        }
    
        // 添加请求的权限数组
        public PermissionHelper requestPermission(String... permissions){
            this.mRequestPermission = permissions;
            return this;
        }
    
        /**
         * 3.1 真正判断和发起请求权限
         */
        public void request() {
            // 3.2 首先判断当前的版本是不是6.0 及以上
            if(!PermissionUtils.isOverMarshmallow()){
                // 3.3 如果不是6.0以上  那么直接执行方法   反射获取执行方法
                // 执行什么方法并不确定 那么我们只能采用注解的方式给方法打一个标记,
                // 然后通过反射去执行。  注解 + 反射  执行Activity里面的callPhone
                PermissionUtils.executeSucceedMethod(mObject,mRequestCode);
                return;
            }
        }
    }
    

    2.2. 处理6.0以下的版本
      对于6.0以下的版本,我们可以直接反射调用执行成功的方法,如果反射不太理解可以看一下这个视频讲解:http://pan.baidu.com/s/1bpqqkGn

        /**
         * 执行成功的方法
         */
        public static void executeSucceedMethod(Object reflectObject, int requestCode) {
            // 获取class中多有的方法
            Method[] methods = reflectObject.getClass().getDeclaredMethods();
    
            // 遍历找我们打了标记的方法
            for (Method method:methods){
                Log.e("TAG",method+"");
                // 获取该方法上面有没有打这个成功的标记
                PermissionSucceed succeedMethod =  method.getAnnotation(PermissionSucceed.class);
                if(succeedMethod != null){
                    // 代表该方法打了标记
                    // 并且我们的请求码必须 requestCode 一样
                    int methodCode = succeedMethod.requestCode();
                    if(methodCode == requestCode){
                        // 这个就是我们要找的成功方法
                        // 反射执行该方法
                        Log.e("TAG","找到了该方法 :"+method);
                        executeMethod(reflectObject,method);
                    }
                }
            }
        }
    
        /**
         * 反射执行该方法
         */
        private static void executeMethod(Object reflectObject,Method method) {
            // 反射执行方法  第一个是传该方法是属于哪个类   第二个参数是反射方法的参数
            try {
                method.setAccessible(true); // 允许执行私有方法
                method.invoke(reflectObject,new Object[]{});
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    

    2.3. 处理6.0以上的版本

        /**
         * 3.1 真正判断和发起请求权限
         */
        public void request() {
            // 3.2 首先判断当前的版本是不是6.0 及以上
            if(!PermissionUtils.isOverMarshmallow()){
                // 3.3 如果不是6.0以上  那么直接执行方法   反射获取执行方法
                // 执行什么方法并不确定 那么我们只能采用注解的方式给方法打一个标记,
                // 然后通过反射去执行。  注解 + 反射  执行Activity里面的callPhone
                PermissionUtils.executeSucceedMethod(mObject,mRequestCode);
                return;
            }
    
            // 3.3 如果是6.0以上  那么首先需要判断权限是否授予
            // 需要申请的权限中 获取没有授予过得权限
            List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(mObject,mRequestPermission);
    
            // 3.3.1 如果授予了 那么我们直接执行方法   反射获取执行方法
            if(deniedPermissions.size() == 0){
                // 全部都是授予过的
                PermissionUtils.executeSucceedMethod(mObject,mRequestCode);
            }else {
                // 3.3.2 如果没有授予 那么我们就申请权限  申请权限
                ActivityCompat.requestPermissions(PermissionUtils.getActivity(mObject),
                        deniedPermissions.toArray(new String[deniedPermissions.size()]),
                        mRequestCode);
            }
        }
    

    2.4. 处理回调
      如果用户同意或是拒绝那么会回调onRequestPermissionsResult(),我们肯定也需要对它做处理,这个方法就很简单了:

        /**
         * 处理申请权限的回调
         */
        public static void requestPermissionsResult(Object object,int requestCode,
                                                    String[] permissions) {
            // 再次获取没有授予的权限
            List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(object,permissions);
    
            if(deniedPermissions.size() == 0){
                // 权限用户都同意授予了
                PermissionUtils.executeSucceedMethod(object,requestCode);
            }else{
                // 你申请的权限中 有用户不同意的
                PermissionUtils.executeFailMethod(object,requestCode);
            }
        }
    

    2.5. 最后的事例

    public class MainActivity extends AppCompatActivity {
        // 打电话权限申请的请求码
        private static final int CALL_PHONE_REQUEST_CODE = 0x0011;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
       public void phoneClick(View view){
            PermissionHelper.with(this).requestCode(CALL_PHONE_REQUEST_CODE)
                    .requestPermission(Manifest.permission.CALL_PHONE).request();
        }
    
        @PermissionSucceed(requestCode =  CALL_PHONE_REQUEST_CODE)
        private void callPhone() {
            Intent intent = new Intent(Intent.ACTION_CALL);
            Uri data = Uri.parse("tel:147****2514");
            intent.setData(data);
            startActivity(intent);
        }
    
        @PermissionFail(requestCode = CALL_PHONE_REQUEST_CODE)
        private void callPhoneFail(){
            Toast.makeText(this,"您拒绝了拨打电话",
                Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        PermissionHelper.requestPermissionsResult(this,
            CALL_PHONE_REQUEST_CODE,permissions);
        }
    }
    

    到最后再处理权限请求的时候会轻松很多,一行代码解决问题,反正别人都这么说,我们甚至可以把onRequestPermissionsResult()的处理写到BaseActivity中,因为权限封装我没有把它写入到基础架构部分,这里我就不处理了。

    这里写图片描述
      
      项目的代码不能够发给大家,里面涉及到后台接口以及数据加密,如果大家感兴趣可以看一下我录的视频:http://pan.baidu.com/s/1bpqqkGn
      
    这里我只附上事例代码地址:
    http://download.csdn.net/detail/z240336124/9683704

    相关文章

      网友评论

      • Android轮子哥:推荐一个简单好用的框架,一句代码搞定权限请求,从未如此简单:https://github.com/getActivity/XXPermissions
      • 兜兜里面没有钱:我照着视频的代码敲下来,不知道为什么走不到拒绝里面。
      • X1a0Yu_:谢谢大佬的分享,学习了,思路棒!!!
      • 异想天开的骑士:请问,这个混淆代码有影响吗?谢谢。
        异想天开的骑士:@红橙Darren 视频中有解决方案吗
        红橙Darren:@愁容 有影响
      • ziabo_yu:我们的做法是在欢迎页把常用的权限都申请一遍,比较特殊的地方再单独申请,用的RxPermission也很方便,几行的事情!
        ziabo_yu: @红橙Darren 可能我们的项目比较小,用到危险权限的地方不多
        红橙Darren:也是可以的,但是可能很大一部分不是这样处理,RxPermissions这个第三方框架的确很不错,也很好用。
      • openGL小白:// 获取该方法上面有没有打这个成功的标记
        PermissionSucceed succeedMethod = method.getAnnotation(PermissionSucceed.class);
        i
        使用部分函数上面的注解,只需要这里反射处理吗?不需要注解定义的相关类?
        反射好像只处理了成功,那下面用到的@PermissionFail(requestCode = CALL_PHONE_REQUEST_CODE) 是不是没被处理
        红橙Darren:做了处理,只是不是在这个地方而已,具体你可以下载事例代码运行一下,希望可以帮到你。

      本文标题:Android 6.0 运行时权限封装框架

      本文链接:https://www.haomeiwen.com/subject/zrkmbttx.html