Android6.0运行权限框架封装

1.概述

  上篇文章文章介绍了Android 6.0 运行时权限处理解析,只是写了运行时申请权限处理,但是并未对其做代码封装,这一次我们做一个彻底的封装处理,供以后项目中使用。

2.框架封装

  2.1.简单事例:

    public class TextActivity extends AppCompatActivity {
          // 打电话权限申请的请求码
          private static final int CALL_PHONE_REQUEST_CODE = 0x0011;

          @Override
          protected void onCreate(Bundle savedInstanceState) {
               super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_text);
          }
         
         /**
          * 检察权限
          */    
          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:130****7927");
              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) {
                      // 授予权限
                      callPhone();
                  } else {
                      // 拒绝权限
                      Toast.makeText(this,"权限被您拒绝了",Toast.LENGTH_SHORT).show();
                  }
              }
          }
      }

  这是从上一篇中复制过来的,没有任何地方改变,如果我们每次申请权限的地方都需要这么写,那就比较麻烦了,那么我们肯定要对 callPhone()onRequestPermissionsResult() 里面的代码进行处理,那么要怎么处理呢?

  2.2.什么方式进行封装

    到底采用什么方式去封装,这个github上面也有很多,这里我才用反射+注解的方式去实现。这里就不在详细介绍了,这里我采用 反射 + 注解 的方式去实现。
    反射 + 注解刚开始不是太了解,看了 辉哥 Darren,的视频文章懂了很多,非常感谢。大家也可以去看看,每篇文章下边都会附带视频,讲解很详细。

  2.3.都需要什么

    1.反射我们需要当前的类,第一个参数反射的类this
    2.我们的请求码,第二个参数请求码用于监听反馈处理
    3.要申请的权限数组,第三个参数传请求权限的数组

  2.4 利用什么方式传递参数

    可以在工具类里面写一个静态的方法一把塞过去。但是在这里我们可以使用链式调用这种方式我们也经常使用,例如:Retrofit,Okhttp,Gilde,甚至是Android自带的的AlertDialog都是使用的这个方式,也采用这种方式,装装B


3 开始封装

  3.1 创建注解文件

	//成功注解
	@Target(ElementType.METHOD)
	@Retention(RetentionPolicy.RUNTIME)
	public @interface PermissionSuccess {
    	public int requestCode();   //请求码
	}
	//失败的注解
	@Target(ElementType.METHOD)
	@Retention(RetentionPolicy.RUNTIME)
	public @interface PermissionFail {
   		 public int requestCode();   //请求码
	}

注解作用:在类,方法,属性上做一个标记,一般配合类反射使用
  Target:表示作用在谁身上,方法METHOD,属性FIELD,类TYPE等等
  @Target(ElementType.METHOD)
  Retention:代表什么时候检测,编译时检测 运行时检测
  @Retention(RetentionPolicy.RUNTIME)

3.2 创建PermissionHelper辅助类

public class PermissionHelper {

    //1.需要传什么参数
    //1.1 Object 可以是Fragment 或 Activity    
    private Object mObject;
    //1.2 int 请求码
    private int mRequestCode;
    //1.3 String[] 需要申请权限数组
    private String[] mRequestPermission;

    public PermissionHelper(Object object) {
        this.mObject = object;
    }

    //1.可以直接方法传递
    public void requestPermission(Activity activity, int requestCode, String[] permissions) {
        PermissionHelper.with(activity).requestCode(requestCode).requestPermission(permissions).request();
    }


    public void requestPermission(Fragment fragment, int requestCode, String[] permissions) {
        PermissionHelper.with(fragment).requestCode(requestCode).requestPermission(permissions).request();
    }


    //2.可以使用链式调用,链式调用返回的都是this,才可以继续调用
    //传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;
    }

    //添加请求权限数组 String[] 想同于 String...
    public PermissionHelper requestPermission(String... permissions) {
        this.mRequestPermission = permissions;
        return this;
    }

    //3.执行链式调用
    public void request() {
        //3.1 首先判断是否是6.0以上版本
        if (!PermissionUtils.isOverMarshmallow()) {
            //如果不是就不需要申请权限,直接执行方法,通过反射获取方法
            //问题:执行哪个方法不确定,需要通过注解方式来声明,通过反射 + 注解执行
            PermissionUtils.executeSuccessMethod(mObject, mRequestCode);
            return;
        }
        //3.2 如果是6.0以上首先判断是否已经给予权限
        //判断需要申请的权限中,用户没有授予过的权限,添加到集合中
        List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(mObject, mRequestPermission);
        //3.2.1 如果授权了,直接执行方法  反射获取执行方法
        //如果没有授予的权限为0,表示都已经授予了,就直接执行
        if (deniedPermissions.size() == 0) {
            PermissionUtils.executeSuccessMethod(mObject, mRequestCode);
        }else {
            //3.2.2 如果没有授权,就申请授权
            ActivityCompat.requestPermissions(PermissionUtils.getActivity(mObject),
                    deniedPermissions.toArray(new String[deniedPermissions.size()]),
                    mRequestCode);
        }
    }

    /**
     * 获取权限的回掉
     * @param object
     * @param requestCode
     * @param permissions
     */
    public static void requestPermissionsResult(Object object, int requestCode, String[] permissions) {
        //再次获取数组中没有授予的权限
        List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(object,permissions);
        if (deniedPermissions.size() == 0){
            //都已经授予了,直接执行方法
            PermissionUtils.executeSuccessMethod(object, requestCode);
        }else {
            //申请的权限中,有用户不同意的
            PermissionUtils.executeFailMethod(object,requestCode);
        }
    }
}

3.3 创建PermissionHelper辅助类

public class PermissionUtils {
	private List<String> deniedPermissions;

	//不允许使用者来new对象,也可以写
    public PermissionUtils() {
        throw new UnsupportedOperationException("Cannot be instantiated");
    }

    /**
     * 判断是否是6.0以上
     * Marshmallow 棉花糖
     */
    public static boolean isOverMarshmallow(){
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

    /**
     * 执行我们成功方法
     * @param reflectObject     类对象
     * @param requestCode       请求码
     */
    public static void executeSuccessMethod(Object reflectObject, int requestCode) {
        //1.获取类中的所以有方法
        Method[] methods = reflectObject.getClass().getDeclaredMethods();
        //2.遍历找到我们方法上打了标记的方法
        for (Method method : methods) {
            //3.获取方法上是否打了标记
            PermissionSuccess permissionSuccess =  method.getAnnotation(PermissionSuccess.class);
            if (permissionSuccess!=null){
                //4.不为空证明该方法打了标记,并判断方法上请求码和申请的是否一样
                int methodCode = permissionSuccess.requestCode();
                if (methodCode == requestCode){
                    //相同就是我们要找的方法,反射执行方法
                    executeMethod(reflectObject,method);
                }
            }
        }
    }

    /**
     * 用户拒绝的权限,执行失败的方法
     * @param reflectObject
     * @param requestCode
     */
    public static void executeFailMethod(Object reflectObject, int requestCode) {
        //1.获取所有的方法
        Method[] methods = reflectObject.getClass().getDeclaredMethods();
        //2.遍历所有的方法,找到失败注解
        for (Method method : methods) {
            PermissionFail permissionFail =  method.getAnnotation(PermissionFail.class);
            int methodCode = permissionFail.requestCode();
            if (methodCode == requestCode){
                //相同是我们要找的方法,反射执行方法
                executeMethod(reflectObject,method);
            }
        }
    }


    /**
     * 执行方法
     * @param reflectObject
     * @param method
     */
    public static void executeMethod(Object reflectObject, Method method) {
        /**
         *  参数1:该方法属于哪个类
         *  参数2:该方法的参数,这里没有
         */
        try {
            method.setAccessible(true); //强制执行私有方法
            method.invoke(reflectObject,new Object[]{});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取没有授予过的权限
     * @param object  Fragment 或者 Activity
     * @param requestPermissions
     * @return
     */
    public static List<String> getDeniedPermissions(Object object, String[] requestPermissions) {
    	//创建数组,将用户未授予的权限添加到一个集合中
        deniedPermissions = new ArrayList<>();
        for (String requestPermission : requestPermissions) {
            //将没有授予过的权限添加到集合
            if (ContextCompat.checkSelfPermission(getActivity(object),requestPermission) == PackageManager.PERMISSION_DENIED){
                deniedPermissions.add(requestPermission);
            }
        }
        return deniedPermissions;
    }

    /**
     * 获取Context上下文
     * @param object
     * @return
     */
    public static Activity getActivity(Object object) {
        if (object instanceof Activity){
            return (Activity) object;
        }
        if (object instanceof Fragment){
            return ((Fragment) object).getActivity();
        }
        return null;
    }
}

4.最后使用


public class TextActivity extends AppCompatActivity {

    // 打电话权限申请的请求码
    private static final int CALL_PHONE_REQUEST_CODE = 0x0011;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text);
    }

    /**
     * 调用打电话,只需一行代码
     * @param view
     */
    public void phoneClick(View view) {
        PermissionHelper.with(this).requestCode(CALL_PHONE_REQUEST_CODE).requestPermission(Manifest.permission.CALL_PHONE).request();
    }

    /**
     * 用户允许成功方法
     **/
    @PermissionSuccess(requestCode = CALL_PHONE_REQUEST_CODE)
    private void callPhone() {
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:130****7927");
        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) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //处理用户的回掉
        PermissionHelper.requestPermissionsResult(this,requestCode,permissions);
    }
}

这样封装后,是不是清晰很多,一行代码解决问题,我们还可以把onRequestPermissionsResult()的处理写到我们的基类BaseActivity中

上一篇:Android EasyPermissions拍照权限管理申请


下一篇:通过AOP的思想 打造万能动态权限申请框架Demo完全解析