動態權限相關的幾個庫分析

同步更新於 權限系列
java

有比較多的權限庫 由淺入深先看簡單的開開胃git

一、PermissionGen

PermissionGen
github

該庫比較早 看提交是3年前了 經過看該庫的readme能夠了解這個庫的使用方式,經過鏈式調用比較易於配置編程


核心類圖以下:api


image.png



將權限涉及到核心api封裝到框架之中,幹掉冗餘函數,使用者只關心功能函數便可。bash

涉及到的比較核心的一個點就是,經過註解的方式直接回調權限成功、失敗的函數
框架


When it succeeded in obtaining permission函數

@PermissionSuccess(requestCode = 100)
public void doSomething(){
	Toast.makeText(this, "Contact permission is granted", Toast.LENGTH_SHORT).show();
}複製代碼

When it failed in obtaining permission學習

@PermissionFail(requestCode = 100)
public void doFailSomething(){
	Toast.makeText(this, "Contact permission is not granted", t.LENGTH_SHORT).show();
}複製代碼

核心的處理邏輯在PermissionGen#requestPermissions(Object object, int requestCode, String[] permissions)中,最終經過反射調取 PermissionFail和PermissionSucess註解的函數gradle

經過這種方式幹掉了冗餘代碼,讓用戶專一於業務的開發


private static void requestPermissions(Object object, int requestCode, String[] permissions){
    if(!Utils.isOverMarshmallow()) {
      doExecuteSuccess(object, requestCode);
      return;
    }
    List<String> 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);
    }
}複製代碼



private static void executeMethod(Object activity, Method executeMethod) {
    if(executeMethod != null){
      try {
        if(!executeMethod.isAccessible()) executeMethod.setAccessible(true);
        executeMethod.invoke(activity, null);
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
}複製代碼


能夠看出反射函數只能無參函數 其中拿到activity或者fragment的註解方法在Utils的方法中,這裏能夠學習一下反射的一些用法,好比查找對應註解的方法



public static <A extends Annotation> Method findMethodWithRequestCode(Class clazz, Class<A> annotation, int requestCode) {
    for(Method method : clazz.getDeclaredMethods()){
      if(method.isAnnotationPresent(annotation)){
        if(isEqualRequestCodeFromAnntation(method, annotation, requestCode)){
          return method;
        }
      }
    }
    return null;
  }複製代碼


小結:


這個庫比較簡單有一些優缺點:


優勢:初步封裝了權限的核心函數的,省去了冗餘代碼;能夠學習反射的一些用法

缺點:

(1)大量使用反射(可使用apt),

(2)api設計不是很合理

鏈式調用每每是平級調用方法,可是如今這個明顯是有前後順序的,一不留神容易寫錯



二、MPermissions


MPermissions

這個是鴻洋在PermissionGen基礎上作了一些優化,做者說是使用apt解決了運行時反射的問題,優化了對外提供的api,由於申請只須要三個參數,拋棄了使用本來類庫的單例的方式,直接一個幾個靜態方法,簡單整潔暴力。


看了一下代碼,主要是核心類MPermissions操做接口,間接操做實現該接口的APT生成類(依賴翻轉,面向接口編程)

image.png



能夠學習的一些點:


2.1 APT 編譯前找不到類

面向接口編程,APT代碼生成代碼實現這個接口就能夠,

權限類的核心能力經過接口提供


public interface PermissionProxy<T> {
    void grant(T source, int requestCode);
    void denied(T source, int requestCode);
    void rationale(T source, int requestCode);
    boolean needShowRationale(int requestCode);
}
複製代碼

功能類跟接口層交互便可


2.2 APT技術


經過APT生成一些重複的模板代碼很是有用,關於APT技術在以前的博客多有說起就再也不贅述了。

不過APT也有它的弊端就是APT 的工做原理是在編譯 class 時,經過 Annotation 生成源代碼,而在 Android 構建的過程當中,像 滴滴出行乘客端 這樣的集成方式,全部的模塊都是 AAR 的方式來集成構建的,沒有機會去同時編譯全部的 class,這時候就須要新的手段來生成代碼了,好比構建gradle的task在編譯前掃描全局結合javapoet生成代碼


在這個庫裏能夠學習一下apt processor的異常處理有助於咱們定位代碼


private void error(Element element, String message, Object... args) {
    if (args.length > 0) {
        message = String.format(message, args);
    }
    processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message, element);
}
複製代碼




小結


做者僅僅是經過APT生成了模板代碼,可是仍是使用到反射生成實現代理接口的實現類



private static PermissionProxy findPermissionProxy(Object activity) {
    try {
        Class clazz = activity.getClass();
        Class injectorClazz = Class.forName(clazz.getName() + SUFFIX);
        return (PermissionProxy) injectorClazz.newInstance();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    throw new RuntimeException(String.format("can not find %s , something when compiler.", activity.getClass().getSimpleName() + SUFFIX));
}
複製代碼


這個APT代理的思想仍是值得咱們去借鑑的

三、PermissionsDispatcher

這個庫目前有7726個start,並且有本身的網站指導說明,儼然是動態權限三方庫的一哥,看來這個庫須要好好分析一下

從官方這個庫使用起來也很是簡單,仔細看了下代碼發現大同小異,跟前面兩個庫使用的方式很像,經過註解的方式標記 權限申請成功、權限事情失敗、權限彈窗說明等函數調用,惟一多的是:

一、須要使用動態權的 Activity or Fragment(we support both) to handle permissions加上RuntimePermissions註解

這個庫更可能是將全部的邏輯處理放在了權限生成類 xxxPermissionDispatcher類,(生成代碼承擔了不少的邏輯處理)而不像MPermission庫中僅僅將用戶使用的功能代碼,好比權限成功、失敗之類的函數規整到生成類中,核心邏輯仍是經過開發者本身代碼處理,這樣更容易寫這個庫,用戶閱讀代碼也比較方便


我的更加傾向於 MPermission

相關文章
相關標籤/搜索