實現方式
暫時只提供了註解反射、apt兩種方式,aop等有時間再加
註解反射流程圖:
apt方式:主要流程和註解方式一樣,activity中添加對應的註解(需要權限、提示用戶爲何要開啓權限、拒絕權限、用戶選擇不再詢問後的提示),在process方法生成的類中處理權限請求邏輯,調用對應的註解方法
關鍵代碼
註解反射:
/**
* 通過反射執行activity中的註解方法
*
* @param activity
* @param requestCode
*/
private static void reflectAnnotationMethod(Activity activity, int requestCode) {
Class<? extends Activity> activityClass = activity.getClass();
Method[] methods = activityClass.getDeclaredMethods();
for (Method method : methods) {
//如果方法是IPermission註解
if (method.isAnnotationPresent(IPermission.class)) {
IPermission iPermission = method.getAnnotation(IPermission.class);
//註解值等於標識碼
if (iPermission.value() == requestCode) {
//判斷返回值是否是void
Type returnType = method.getGenericReturnType();
if (!"void".equals(returnType.toString())) {
throw new RuntimeException(method.getName() + " returnType must be void !!!");
}
//判斷是否有參數
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 0) {
throw new RuntimeException(method.getName() + " parameterTypes must be null !!!");
}
//如果方法是私有的,設置可以訪問
if (!method.isAccessible()) method.setAccessible(true);
try {
method.invoke(activity);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
apt方式:
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 獲取MainActivity中所有帶NeedsPermission註解的方法
Set<? extends Element> needsPermissionSet = roundEnvironment.getElementsAnnotatedWith(NeedsPermission.class);
// 保存鍵值對,key是com.netease.permission.MainActivity value是所有帶NeedsPermission註解的方法集合
Map<String, List<ExecutableElement>> needsPermissionMap = new HashMap<>();
// 遍歷所有帶NeedsPermission註解的方法
for (Element element : needsPermissionSet) {
// 轉成原始屬性元素(結構體元素)
ExecutableElement executableElement = (ExecutableElement) element;
// 通過屬性元素獲取它所屬的MainActivity類名,如:com.netease.permission.MainActivity
String activityName = getActivityName(executableElement);
// 從緩存集合中獲取MainActivity所有帶NeedsPermission註解的方法集合
List<ExecutableElement> list = needsPermissionMap.get(activityName);
if (list == null) {
list = new ArrayList<>();
// 先加入map集合,引用變量list可以動態改變值
needsPermissionMap.put(activityName, list);
}
// 將MainActivity所有帶NeedsPermission註解的方法加入到list集合
list.add(executableElement);
// 測試打印:每個方法的名字
System.out.println("NeedsPermission executableElement >>> " + executableElement.getSimpleName().toString());
}
// 獲取MainActivity中所有帶OnNeverAskAgain註解的方法
Set<? extends Element> onNeverAskAgainSet = roundEnvironment.getElementsAnnotatedWith(OnNeverAskAgain.class);
Map<String, List<ExecutableElement>> onNeverAskAgainMap = new HashMap<>();
for (Element element : onNeverAskAgainSet) {
ExecutableElement executableElement = (ExecutableElement) element;
String activityName = getActivityName(executableElement);
List<ExecutableElement> list = onNeverAskAgainMap.get(activityName);
if (list == null) {
list = new ArrayList<>();
onNeverAskAgainMap.put(activityName, list);
}
list.add(executableElement);
System.out.println("executableElement >>> " + executableElement.getSimpleName().toString());
}
// 獲取MainActivity中所有帶OnPermissionDenied註解的方法
Set<? extends Element> onPermissionDeniedSet = roundEnvironment.getElementsAnnotatedWith(OnPermissionDenied.class);
Map<String, List<ExecutableElement>> onPermissionDeniedMap = new HashMap<>();
for (Element element : onPermissionDeniedSet) {
ExecutableElement executableElement = (ExecutableElement) element;
String activityName = getActivityName(executableElement);
List<ExecutableElement> list = onPermissionDeniedMap.get(activityName);
if (list == null) {
list = new ArrayList<>();
onPermissionDeniedMap.put(activityName, list);
}
list.add(executableElement);
System.out.println("executableElement >>> " + executableElement.getSimpleName().toString());
}
// 獲取MainActivity中所有帶OnShowRationale註解的方法
Set<? extends Element> onShowRationaleMapSet = roundEnvironment.getElementsAnnotatedWith(OnShowRationale.class);
Map<String, List<ExecutableElement>> onShowRationaleMap = new HashMap<>();
for (Element element : onShowRationaleMapSet) {
ExecutableElement executableElement = (ExecutableElement) element;
String activityName = getActivityName(executableElement);
List<ExecutableElement> list = onShowRationaleMap.get(activityName);
if (list == null) {
list = new ArrayList<>();
onShowRationaleMap.put(activityName, list);
}
list.add(executableElement);
System.out.println("executableElement >>> " + executableElement.getSimpleName().toString());
}
//----------------------------------造幣過程------------------------------------
// 獲取Activity完整的字符串類名(包名 + 類名)
for (String activityName : needsPermissionMap.keySet()) {
// 獲取"com.netease.permission.MainActivity"中所有控件方法的集合
List<ExecutableElement> needsPermissionElements = needsPermissionMap.get(activityName);
List<ExecutableElement> onNeverAskAgainElements = onNeverAskAgainMap.get(activityName);
List<ExecutableElement> onPermissionDeniedElements = onPermissionDeniedMap.get(activityName);
List<ExecutableElement> onShowRationaleElements = onShowRationaleMap.get(activityName);
final String CLASS_SUFFIX = "$Permission";
Filer filer = processingEnv.getFiler();
try {
// 創建一個新的源文件(Class),並返回一個對象以允許寫入它
JavaFileObject javaFileObject = filer.createSourceFile(activityName + CLASS_SUFFIX);
// 通過方法標籤獲取包名標籤(任意一個屬性標籤的父節點都是同一個包名)
String packageName = getPackageName(needsPermissionElements.get(0));
// 定義Writer對象,開啓造幣過程
Writer writer = javaFileObject.openWriter();
// 類名:MainActivity$Permission,不是com.netease.permission.MainActivity$Permission
// 通過屬性元素獲取它所屬的MainActivity類名,再拼接後結果爲:MainActivity$Permission
String activitySimpleName = needsPermissionElements.get(0).getEnclosingElement()
.getSimpleName().toString() + CLASS_SUFFIX;
System.out.println("activityName >>> " + activityName + "\nactivitySimpleName >>> " + activitySimpleName);
System.out.println("開始造幣 ----------------------------------->");
// 生成包
writer.write("package " + packageName + ";\n");
// 生成要導入的接口類(必須手動導入)
writer.write("import com.zy.apt_library.listener.RequestPermission;\n");
writer.write("import com.zy.apt_library.listener.PermissionRequest;\n");
writer.write("import com.zy.apt_library.listener.PermissionSetting;\n");
writer.write("import com.zy.apt_library.util.PermissionUtils;\n");
writer.write("import androidx.core.app.ActivityCompat;\n");
writer.write("import androidx.annotation.NonNull;\n");
writer.write("import java.lang.ref.WeakReference;\n");
writer.write("import android.provider.Settings;\n");
writer.write("import android.content.Intent;\n");
writer.write("import android.net.Uri;\n");
// 生成類
writer.write("public class " + activitySimpleName +
" implements RequestPermission<" + activityName + "> {\n");
// 生成常量屬性
writer.write("private static final int REQUEST_SHOWCAMERA = 666;\n");
writer.write("private static String[] PERMISSION_SHOWCAMERA;\n");
// 生成requestPermission方法
writer.write("public void requestPermission(" + activityName + " target, String[] permissions) {\n");
writer.write("PERMISSION_SHOWCAMERA = permissions;\n");
writer.write("if (PermissionUtils.hasSelfPermissions(target, PERMISSION_SHOWCAMERA)) {\n");
// 循環生成MainActivity每個權限申請方法
for (ExecutableElement executableElement : needsPermissionElements) {
// 獲取方法名
String methodName = executableElement.getSimpleName().toString();
// 調用申請權限方法
writer.write("target." + methodName + "();\n");
}
writer.write("} else if (PermissionUtils.shouldShowRequestPermissionRationale(target, PERMISSION_SHOWCAMERA)) {\n");
// 循環生成MainActivity每個提示用戶爲何要開啓權限方法
for (ExecutableElement executableElement : onShowRationaleElements) {
// 獲取方法名
String methodName = executableElement.getSimpleName().toString();
// 調用提示用戶爲何要開啓權限方法
writer.write("target." + methodName + "(new PermissionRequestImpl(target));\n");
}
writer.write("} else {\n");
writer.write("ActivityCompat.requestPermissions(target, PERMISSION_SHOWCAMERA, REQUEST_SHOWCAMERA);\n}\n}\n");
// 生成onRequestPermissionsResult方法
writer.write("public void onRequestPermissionsResult(" + activityName + " target, int requestCode, @NonNull int[] grantResults) {");
writer.write("switch(requestCode) {\n");
writer.write("case REQUEST_SHOWCAMERA:\n");
writer.write("if (PermissionUtils.verifyPermissions(grantResults)) {\n");
// 循環生成MainActivity每個權限申請方法
for (ExecutableElement executableElement : needsPermissionElements) {
// 獲取方法名
String methodName = executableElement.getSimpleName().toString();
// 調用申請權限方法
writer.write("target." + methodName + "();\n");
}
writer.write("} else if (!PermissionUtils.shouldShowRequestPermissionRationale(target, PERMISSION_SHOWCAMERA)) {\n");
// 循環生成MainActivity每個不再詢問後的提示
for (ExecutableElement executableElement : onNeverAskAgainElements) {
// 獲取方法名
String methodName = executableElement.getSimpleName().toString();
// 調用不再詢問後的提示
writer.write("target." + methodName + "(new PermissionSettingImpl(target));\n");
}
writer.write("} else {\n");
// 循環生成MainActivity每個拒絕時的提示方法
for (ExecutableElement executableElement : onPermissionDeniedElements) {
// 獲取方法名
String methodName = executableElement.getSimpleName().toString();
// 調用拒絕時的提示方法
writer.write("target." + methodName + "();\n");
}
writer.write("}\nbreak;\ndefault:\nbreak;\n}\n}\n");
// 生成接口實現類:PermissionRequestImpl implements PermissionRequest
writer.write("private static final class PermissionRequestImpl implements PermissionRequest {\n");
writer.write("private final WeakReference<" + activityName + "> weakTarget;\n");
writer.write("private PermissionRequestImpl(" + activityName + " target) {\n");
writer.write("this.weakTarget = new WeakReference(target);\n}\n");
writer.write("public void proceed() {\n");
writer.write(activityName + " target = (" + activityName + ")this.weakTarget.get();\n");
writer.write("if (target != null) {\n");
writer.write("ActivityCompat.requestPermissions(target, PERMISSION_SHOWCAMERA, REQUEST_SHOWCAMERA);\n}\n}\n}\n");
// 生成接口實現類:PermissionSettingImpl implements PermissionSetting
writer.write("private static final class PermissionSettingImpl implements PermissionSetting {\n");
writer.write("private final WeakReference<" + activityName + "> weakTarget;\n");
writer.write("private PermissionSettingImpl(" + activityName + " target) {\n");
writer.write("this.weakTarget = new WeakReference(target);\n}\n");
writer.write("public void setting(int settingCode) {\n");
writer.write(activityName + " target = (" + activityName + ")this.weakTarget.get();\n");
writer.write("if (target != null) {\n");
writer.write("Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\n");
writer.write("Uri uri = Uri.fromParts(\"package\", target.getPackageName(), null);\n");
writer.write("intent.setData(uri);\n");
writer.write("target.startActivityForResult(intent, settingCode);\n}\n}\n}\n");
// 最後結束標籤,造幣完成
writer.write("\n}");
System.out.println("結束 ----------------------------------->");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}