Synchronize updates to permission series

There are more permissions library from shallow to deep first look at the simple appetizer

1, PermissionGen

PermissionGen

The library was committed 3 years ago. You can see how the library is used by looking at the readme of the library, which is easy to configure through chained calls

The core class diagram is as follows:

Encapsulate permissions related to core APIS in the framework, eliminate redundant functions, and users only care about functional functions.

One of the core points involved is the ability to call back directly to functions with permissions that failed or succeeded via annotations

When it succeeded in obtaining permission

@PermissionSuccess(requestCode = 100)
public void doSomething(){
	Toast.makeText(this, "Contact permission is granted", Toast.LENGTH_SHORT).show();
}
Copy the code

When it failed in obtaining permission

@PermissionFail(requestCode = 100)
public void doFailSomething(){
	Toast.makeText(this, "Contact permission is not granted", t.LENGTH_SHORT).show();
}
Copy the code

PermissionGen#requestPermissions(Object Object, int requestCode, String[] permissions) The function that finally calls the PermissionFail and PermissionSucess annotations through reflection

This eliminates redundant code and allows users to focus on business development

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(); }}}Copy the code

In the Utils method, you can learn how to use reflection, such as finding the corresponding annotation method

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;
  }
Copy the code

Summary:

This library is relatively simple and has some advantages and disadvantages:

Advantages: preliminary encapsulation of the authority of the core function, eliminating redundant code; You can learn some uses of reflection

Disadvantages:

(1) Extensive use of reflection (apt can be used),

(2) THE API design is not very reasonable

Chain calls are usually horizontal calls to methods, but this one is obviously sequential and easy to write wrong

2, MPermissions

MPermissions

This is some optimization made by Hongyang on the basis of PermissionGen. According to the author, APT has solved the problem of runtime reflection and optimized the API provided to the outside world. Because application only needs three parameters, it has abandoned the singleton method of the original class library and directly has several static methods, which is simple, clean and violent.

I have a look at the code, mainly the core class MPermissions operates the interface, and indirectly operates the APT generation class that implements the interface (dependent flip, interface oriented programming).

Some things to learn:

2.1 APT failed to find classes before compiling

Interface oriented programming, APT code generation code implementation of this interface can be,

The core capabilities of a permission class are provided through an interface

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);
}
Copy the code

Function classes interact with the interface layer

2.2 APT technology

It is very useful to generate some duplicate template code with APT, which has been covered in previous blogs.

However, APT also has its disadvantages. The working principle of APT is to generate source code through Annotation when compiling class. However, in the process of Android construction, integration methods like Didi Chuxing Passenger terminal are integrated and constructed by AAR. There is no chance to compile all classes at the same time, so new methods of generating code are needed, such as building Gradle tasks that scan globally and generate javapoet code before compiling

In this library you can learn apt Processor exception handling to help us locate code

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);
}
Copy the code

summary

The author only generates the template code through APT, but still uses reflection to generate the implementation class that implements the proxy interface

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));
}
Copy the code

The idea of APT agent is worth learning from

3, PermissionsDispatcher

This library has 7726 starts, and has its own website instructions. It is like the first brother of the three libraries of dynamic permissions, so it needs to be analyzed

From the official use of this library is also very simple, a careful look at the code found similar to the previous two libraries use the way, through annotations to mark the permission application success, permission things failed, permission popup description and other function calls, the only more is:

Activity or Fragment(we support both) to handle Permissions

This library puts all the logical processing in the permission generation class xxxPermissionDispatcher (the generated code does a lot of the logical processing), rather than the MPermission library just putting the user-used function code, such as permission success and failure functions, into the generated class. The core logic is handled by the developer’s own code, which makes it easier to write the library and easier for users to read the code

Personally, I prefer MPermission