实现思路:搭配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;
List<String> permissions;
List<String> successPermissions;
List<String> failurePermissions;
public List<String> getSuccessPermissions() {
return successPermissions;
}
public List<String> getFailurePermissions() {
return failurePermissions;
}
public int getRequestCode() {
return requestCode;
}
public int getResultCode() {
return resultCode;
}
public List<String> 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<String> permissions;
List<String> successPermissions;
List<String> 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<String> permissions) {
this.permissions = permissions;
return this;
}
public Builder setSuccessPermissions(List<String> successPermissions) {
this.successPermissions = successPermissions;
return this;
}
public Builder setFailurePermissions(List<String> 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, List<String> perms) {
}
/**
* dialog的取消按钮也会回调这个方法
*/
@Override
public void onPermissionsDenied(int requestCode, List<String> 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<String> perms = new ArrayList<>();
List<String> successPermissions = new ArrayList<>();
List<String> 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会重新对该方法进行改造。具体原理涉及到字节码改造了,不作详细说明,因为我也了解不深 哈哈哈哈。