@SuppressWarnings("UnnecessaryLocalVariable")
    private MethodSpec createMethodForRequiresPermission(TypeElement typeElement, Element e,
                                                         RequiresPermission.Before before,
                                                         RequiresPermission.OnDenied onDenied,
                                                         RequiresPermission requiresPermission)
            throws ClassNotFoundException {

        String methodName = e.getSimpleName().toString();

        // Retrieve all params.
        List<ParameterSpec> parameterSpecs = new ArrayList<>();
        ExecutableElement exe = MoreElements.asExecutable(e);
        List<? extends VariableElement> varList = exe.getParameters();
        for (VariableElement ve : varList) {
            TypeMirror tm = ve.asType();
            TypeName tn = TypeName.get(tm);
            ParameterSpec ps = ParameterSpec.builder(tn, ve.toString(), FINAL).build();
            parameterSpecs.add(ps);
        }

        // Method name.
        methodName += requiresPermission.methodSubFix();

        // Permissions var.
        String[] perms = requiresPermission.value();
        StringBuilder permStatement = new StringBuilder("String permissions[] = new String[]{");
        for (String ignored : perms) {
            permStatement.append("$S").append(", ");
        }
        permStatement.append("}");
        Object[] permArgs = perms;

        int requestCode = REQUEST_CODE.incrementAndGet();

        String methodToCallInRunnable = e.getSimpleName().toString();
        StringBuilder onGrantPassingArgs = new StringBuilder("host." + methodToCallInRunnable + "(");
        for (int i = 0; i < parameterSpecs.size(); i++) {
            ParameterSpec parameterSpec = parameterSpecs.get(i);
            if (i != parameterSpecs.size() - 1)
                onGrantPassingArgs.append(parameterSpec.name).append(", ");
            else onGrantPassingArgs.append(parameterSpec.name);
        }
        onGrantPassingArgs.append(");");

        // OnBefore.
        String onBeforeMethodName = null;
        if (before != null) onBeforeMethodName = before.value();
        String onBeforeCode = before == null ? ""
                : "host." + onBeforeMethodName + "();\n";

        // OnDenied.
        String onDeniedMethodName = null;
        if (onDenied != null) onDeniedMethodName = onDenied.value();
        String onDeniedCode = onDenied == null ? ""
                :
                "Runnable r2 = new Runnable() {\n" +
                        "            @Override\n" +
                        "            public void run() {\n" +
                        "                host." + onDeniedMethodName + "();\n" +
                        "            }\n" +
                        "        };\n" +
                        "ON_DENY_METHODS_MAP.put(code, r2);\n";

        // Check host is Activity or Fragment.
        boolean isActivity;
        boolean isFragment;

        isActivity = MoreTypes.isTargetType(typeElement, "android.app.Activity");
        isFragment = MoreTypes.isTargetType(typeElement, "android.app.Fragment")
                || MoreTypes.isTargetType(typeElement, "androidx.fragment.app.Fragment");

        if (!isActivity && !isFragment) {
            mErrorReporter.abortWithError("Only Activity or Fragment is accepted", typeElement);
        }

        MethodSpec.Builder methodSpecBuilder =
                MethodSpec.methodBuilder(methodName)
                        .addParameters(parameterSpecs)
                        .addParameter(ClassName.bestGuess(typeElement.getQualifiedName().toString()), "host", FINAL)
                        .addStatement(permStatement.toString(), permArgs)
                        .addCode(String.format("if (checkSelfPermissions(%s, permissions))" +
                                        "{" +
                                        "" + onGrantPassingArgs.toString() + "\n" +
                                        " return;}\n",
                                isActivity ? "host" : "host.getActivity()"))
                        .addCode(onBeforeCode)
                        .addStatement("int code = $L", requestCode)

                        .addCode("Runnable r = new Runnable() {\n" +
                                "            @Override\n" +
                                "            public void run() {\n" +
                                "                " +
                                onGrantPassingArgs.toString() + "\n" +
                                "            }\n" +
                                "        };\n")
                        .addStatement("ON_GRANT_METHODS_MAP.put(code, r)")
                        .addCode(onDeniedCode)
                        .addStatement(
                                isActivity ?
                                        "androidx.core.app.ActivityCompat.requestPermissions(host, permissions, code)"
                                        : "host.requestPermissions(permissions, code)")
                        .addModifiers(Modifier.STATIC)
                        .addModifiers(Modifier.FINAL);
        return methodSpecBuilder.build();
    }
Created by guohao4 on 2017/9/6.
Email: Tornaco@163.com
android/annotation_processors/permission-requester-compiler/src/main/java/github/tornaco/permission/compiler/RuntimePermissionsCompiler.java