实现思路:搭配AspectJ切面思想,对需要请求权限的方法进行拦截修改(Around语法),Around语法的作用主要是用来修改需要切入的方法以及方法的参数,参照这一便利,我们在定义的切面方法中新启动一个透明主题的activity作一个权限请求的统一处理的界面,搭配
EasyPermissions权限请求框架,这里作为方便,其实完全可以应业务要求自己封装,
我们可以在将请求权限的结果作为方法的参数进行返回。具体代码思路如下:
//权限请求方法注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface PermissionCheck { String[] value() default {}; int requestCode(); }
//封装权限请求code 返回结果的bean类
public class PermissionsResult { int requestCode; int resultCode; Listpermissions; List successPermissions; List failurePermissions; public List getSuccessPermissions() { return successPermissions; } public List getFailurePermissions() { return failurePermissions; } public int getRequestCode() { return requestCode; } public int getResultCode() { return resultCode; } public List getPermissions() { return permissions; } public PermissionsResult(Builder builder) { this.requestCode = builder.requestCode; this.resultCode = builder.resultCode; this.permissions = builder.permissions; this.successPermissions = builder.successPermissions; this.failurePermissions = builder.failurePermissions; } public static class Builder{ int requestCode; int resultCode; List permissions; List successPermissions; List failurePermissions; public Builder() { } public Builder setRequestCode(int requestCode) { this.requestCode = requestCode; return this; } public Builder setResultCode(int resultCode) { this.resultCode = resultCode; return this; } public Builder setPermissions(List permissions) { this.permissions = permissions; return this; } public Builder setSuccessPermissions(List successPermissions) { this.successPermissions = successPermissions; return this; } public Builder setFailurePermissions(List failurePermissions) { this.failurePermissions = failurePermissions; return this; } public PermissionsResult build(){ return new PermissionsResult(this); } } }
//AspectJ类中定义的切面方法
@Around("call(* *(xx.xx.xx.PermissionsResult)) && @annotation(permissionCheck)") public Object check(final ProceedingJoinPoint point, PermissionCheck permissionCheck){ Log.e("---", "进入切面"); Object target = point.getTarget(); if(null == target) return null; Context context = null; if (target instanceof Activity) { context = (Context) target; } else if (target instanceof Fragment) { context = ((Fragment) target).getActivity(); }else if(target instanceof BaseViewModel){ context = ((BaseViewModel) target).getApplication(); }else if(target instanceof SystemHeadCallBack){ // context = ((SystemHeadCallBack) target).getmContext(); }else if(target instanceof Service){ context = ((Service) target).getApplicationContext(); } String[] permissions = permissionCheck.value(); Object[] objects = new Object[1]; if (context != null) { //做权限是否有的判断 if (EasyPermissions.hasPermissions(context, permissions)) { try { objects[0] = point.proceed(new Object[]{new PermissionsResult.Builder() .setResultCode(1) .setSuccessPermissions(Arrays.asList(permissionCheck.value())).build()}); } catch (Throwable throwable) { throwable.printStackTrace(); } } else { int requestCode = permissionCheck.requestCode(); PermissionCheckActivity.startPermissionCheckActivity( context, permissions, requestCode , new PermissionBack() { @Override public void permissionsCallBack(PermissionsResult permissionsResult) { int returnRequestCode = permissionsResult.getRequestCode(); if(requestCode == returnRequestCode){ //校验 try { objects[0] = point.proceed(new Object[]{permissionsResult}); } catch (Throwable throwable) { throwable.printStackTrace(); } } } } ); } } return objects[0]; }
//透明主题的activity
public class PermissionCheckActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { public static PermissionBack permissionBack; int requestCode; public static void startPermissionCheckActivity(Context context, String[] permissions, int requestCode, PermissionBack back){ Intent intent = new Intent(context, PermissionCheckActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); Bundle bundle = new Bundle(); bundle.putStringArray("permissions", permissions); bundle.putInt("requestCode", requestCode); intent.putExtras(bundle); permissionBack = back; context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_FULLSCREEN); StatusBarCompat.translucentStatusBar(this, true, false, getResources().getColor(R.color.transparent_00000000)); super.onCreate(savedInstanceState); Intent intent = getIntent(); Bundle extras = intent.getExtras(); if (null == extras) return; requestCode = Objects.requireNonNull(extras).getInt("requestCode"); String[] permissions = extras.getStringArray("permissions"); if (permissions == null || permissions.length <= 0) { finish(); } else { //首次会直接请求权限,如果之前权限请求拒绝过 那么就弹提示开启权限的框 确定之后再去请求权限 EasyPermissions.requestPermissions(this, getString(R.string.post_message_albums_permission), requestCode, permissions); } } /** * */ @Override public void onPermissionsGranted(int requestCode, Listperms) { } /** * dialog的取消按钮也会回调这个方法 */ @Override public void onPermissionsDenied(int requestCode, List perms) { finish(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); if(grantResults.length <= 0){ return; } boolean isSuccess = true; List perms = new ArrayList<>(); List successPermissions = new ArrayList<>(); List failurePermissions = new ArrayList<>(); for (int i = 0;i < grantResults.length;i++){ if(grantResults[i] == -1){ // -1表示该权限是被拒绝了的 Log.e("--onRequestPermission", permissions[i] + "授权失败"); failurePermissions.add(permissions[i]); isSuccess = false; }else { successPermissions.add(permissions[i]); Log.e("--onRequestPermission", permissions[i] + "授权成功"); } perms.add(permissions[i]); } permissionBack.permissionsCallBack(new PermissionsResult.Builder() .setRequestCode(requestCode) .setPermissions(perms) .setSuccessPermissions(successPermissions) .setFailurePermissions(failurePermissions) .setResultCode(isSuccess ? 1 : 0).build()); finish(); }
在透明Activity中将权限请求结果进行回调到切面方法中,调用
point.proceed(new Object[]{permissionsResult});将权限请求结果的值作为参数传入到proceed方法.
具体使用:
@PermissionCheck(value = { Manifest.permission.ACCESS_FINE_LOCATION}, requestCode = 10000) public Object check(PermissionsResult result){ if(null == result){ return "1"; } int resultCode = result.getResultCode(); // TODO: 2019/11/14 根据返回的值来确定做什么逻辑 Log.e("--check权限返回code", resultCode + ""); return "2"; }
在需要作权限请求的位置 直接调用 check(null);参数可以随意传,因为编译代码时AspectJ会重新对该方法进行改造。具体原理涉及到字节码改造了,不作详细说明,因为我也了解不深 哈哈哈哈。