简单粗暴的动态权限虽然看上去步骤也就那么几步,但是如果访问的权限多了。重复写同样的代码也会很麻烦
所以,需要一个助手,那简单化,更加容易操作:利用反射加注解

写一个助手类
PermissionHelper
在这个助手类中,需要传递三个参数 
Object Fragment or Activtiy
int 请求码
String... 需要请求的权限

用链式调用 把这些参数添加进来

//链式调用
    //Activity
    public static PermissionHelper with(Activity activity){
        return new PermissionHelper(activity);
    }
    //Fragment
    public static PermissionHelper with(Fragment fragment){
        return new PermissionHelper(fragment);
    }
    //请求码
    public PermissionHelper requesCode(int requesCode){
        this.mRequesCode = requesCode;
        return this;
    }
    //请求的权限
    public PermissionHelper permissions(String... permissions){
        this.mRequestPermission = permissions;
        return this;
    }
    
   

  不为其他,就是为了感觉高大上
接着就是判断和请求了


PermissionHelper.with(this).requesCode(CLAA_PHONE_REQUEST_CODE)
                .permissions(Manifest.permission.CALL_PHONE).request(); //在request()方法中执行

在这个方法中。按照如下步骤
1:判断当前用户的手机是不是6.0版本及以上
创建一个动态申请权限的工具类

PermissionUtils //在这个类中的isOverMarshmallow()方法做判断是不是6.0 及以上
    /**
     * 判断是不是6.0以上版本
     * Marshmallow 棉花糖 6.0 23
     * @return
     */
    public static boolean isOverMarshmallow(){
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

2:如果不是就直接执行注解标准的方法


@Target(ElementType.METHOD)//放在什么上面 放在方法上面
@Retention(RetentionPolicy.RUNTIME) //什么时候运行
public @interface PermissionSucceed { //成功的注解
    public int requestCode();//放一个请求码
}

//也是在PermissionUtils工具类中做处理
public static void executeSuccdMethod(Object object, int requesCode) { //区别申请不懂的权限有一个很重要的东西就是请求码
        //执行成功方法
        //获取reflectClass 里面的所有方法
        Method[] declaredMethods = object.getClass().getDeclaredMethods();
        //遍历我们打了标记的方法
        for (Method declaredMethod : declaredMethods) {
//            Log.e("YacaToy",""+declaredMethod);
            //获取这个方法 有没有打这个成功的标记
            PermissionSucceed annotation = declaredMethod.getAnnotation(PermissionSucceed.class);
            if (annotation != null){
                //不等于空的时候 代表打了标记
                //并且我们的请求码必须和 mRequesCode 一样
                int methodCode = annotation.requestCode();
                if (methodCode == requesCode){
                    //这就是执行的成功方法
                    //反射执行方法
                    //找到了该方法
                    executeMethod(object,declaredMethod);
                }
            }
        }
    }

 



private static void executeMethod(Object object, Method annotation) {
        //反射执行方法 第一个是传该方法是属于那个类里面 第二个参数 是传该
        try {
            annotation.setAccessible(true); //允许执行私有方法
//            Log.e("YacaToy","找到了"+annotation);
            annotation.invoke(object,new Object[]{});
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    

如果不是的6.0版本及以上的话,就不需要申请权限或者判断是否允许权限。就直接反射直接执行代码快
那么如果是6.0 及以上的话,就还要申请权限。基本原理还是和那个简单粗暴的动态申请权限一样的
3:我们需要申请的权限,但是还没有申请过的权限--->拿到这个集合



     /**
     * 获取没有授予过的的权限
     * @param object Activity or Fragmet
     * @param requestPermissions
     * @return 没有授予过的权限
     */
    public static List<String> getDeniedPermissions(Object object, String[] requestPermissions) {
        List<String>  deniedPermissions = new ArrayList<>();
        for (String request : requestPermissions) {
            //把没有授予过的权限加入集合当中来
            //ContextCompat.checkSelfPermission(getActivity(object),request)== PackageManager.PERMISSION_DENIED //判断是否允许
            if (ContextCompat.checkSelfPermission(getActivity(object),request)
                    == PackageManager.PERMISSION_DENIED){
                deniedPermissions.add(request);
            }
        }
        return deniedPermissions;
    }

如果全部允许的话,那样就直接执行方法。如果没有允许的就要动态申请权限


//3.3.1 如果授予了 那么我们直接执行方法
        if (deniedPermissions.size() == 0){
            //全部都是授予过的
            //就直接执行
            PermissionUtils.executeSuccdMethod(mObject,mRequesCode);
        }else {
            //3.3.2 如果没有,那么就申请权限
            //String[]  arr = new String[list.size];  list.toArray(arr);//此时arr就有了list中的值了
            //集合转换成数组 (String[])
            ActivityCompat.requestPermissions(PermissionUtils.getActivity(mObject),
                    deniedPermissions.toArray(new String[deniedPermissions.size()]),
                    mRequesCode);
        }

同样的要拿到请求的返回值,也就要在onRequestPermissionsResult方法中做处理



 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //在动态申请权限的工具类中做处理
        PermissionUtils.requestPermissionResult(this, requestCode, permissions);
    }

   
/**
     * 处理申请权限的回调
     * @param object
     * @param requestCode
     * @param permissions
     */
    public static void requestPermissionResult(
            Object object, int requestCode, String[] permissions) {
        //再次拿到需到集合返回 
        List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(object, permissions);
        if (deniedPermissions.size() == 0){
            //权限用户同意授予了
            PermissionUtils.executeSuccdMethod(object,requestCode);
        }else{
            //如果集合中还是有的元素的话,就说明用户要没有允许。做失败的处理。同样是反射加注解执行方法代码块
            //你申请的权限中,有用户不同意的权限
            PermissionUtils.executeFailMethod(object,requestCode);
        }
    }


 //执行失败的方法
    private static void executeFailMethod(Object object, int requestCode) {
        //执行失败方法
        //获取object 里面的所有方法
        Method[] declaredMethods = object.getClass().getDeclaredMethods();
        //遍历我们打了标记的方法
        for (Method declaredMethod : declaredMethods) {
//            Log.e("YacaToy",""+declaredMethod);
            //获取这个方法 有没有打这个成功的标记 
            //PermissionFail 是失败的注解
            PermissionFail annotation = declaredMethod.getAnnotation(PermissionFail.class);
            if (annotation != null){
                //不等于空的时候 代表打了标记
                //并且我们的请求码必须和 mRequesCode 一样
                int methodCode = annotation.requestCode();
                if (methodCode == requestCode){
                    //这就是执行的成功方法
                    //反射执行方法
                    //找到了该方法
                    executeMethod(object,declaredMethod);
                }
            }
        }
    }
    

好了:以上就是全部的代码。
如果有不懂的,推荐一篇写的更好的(因为我也是看他写的学到的)

Android 6.0 运行时权限封装框架


YacaToy
2 声望3 粉丝