IT评测·应用市场-qidao123.com技术社区

标题: Android怎样通过aspectj打造一个无侵入式动态权限申请框架 [打印本页]

作者: 美食家大橙子    时间: 前天 22:46
标题: Android怎样通过aspectj打造一个无侵入式动态权限申请框架
目次
一,背景
二,通过Aspectj管理全部的注解
三,配置注解 
四,通过空白Activity完成真正的权限申请 
五,引入依赖配置 


一,背景

在Activity或者fragment中,写在几个方法写一些解释,用来表现权限申请成功,申请失败,多次拒绝。同时需要无侵入式,让业务开发者尽大概的少些代码,把焦点的业务逻辑下沉到框架层

二,通过Aspectj管理全部的注解

它的作用就是劫持被解释的方法的执行。我在ASPECT中配置拦截@permission解释的方法。先做判断。如果没有相识过Aspect的话,AOP面向切面编程,各人应该听说过,它可以用来配置事务、做日记、权限验证、在用户哀求时做一些处置惩罚等等。而用@Aspect做一个切面,就可以直接实现。
  1. package com.example.myapplication;
  2. import android.app.Activity;
  3. import android.app.Service;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.pm.PackageManager;
  7. import org.aspectj.lang.ProceedingJoinPoint;
  8. import org.aspectj.lang.annotation.Around;
  9. import org.aspectj.lang.annotation.Aspect;
  10. import org.aspectj.lang.annotation.Pointcut;
  11. import org.aspectj.lang.reflect.MethodSignature;
  12. import java.lang.reflect.Method;
  13. import androidx.core.content.ContextCompat;
  14. import androidx.fragment.app.Fragment;
  15. import androidx.fragment.app.FragmentActivity;
  16. @Aspect
  17. public class PermissionAspect {
  18.     //com.example.myapplication
  19.     private static final String POINTCUT_METHOD = "execution(@com.example.myapplication.Permission * *(..))";
  20.     @Pointcut(POINTCUT_METHOD)
  21.     public void methodAnnotatedWithPermission() {
  22.     }
  23.     @Around("methodAnnotatedWithPermission()")
  24.     public Object permissionMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
  25.         MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  26.         Method method = signature.getMethod();
  27.         Permission permission = method.getAnnotation(Permission.class);
  28.         String[] permissions = permission.value();
  29.         int requestCode = permission.requestCode();
  30.         Object object = joinPoint.getThis();
  31.         Context context = null;
  32.         if (object instanceof Activity) {
  33.             context = (Activity) object;
  34.         } else if (object instanceof FragmentActivity) {
  35.             context = (FragmentActivity) object;
  36.         } else if (object instanceof Fragment) {
  37.             context = ((Fragment) object).getContext();
  38.         } else if (object instanceof Service) {
  39.             context = (Service) object;
  40.         }
  41.         Object o = null;
  42.         if (checkPermissions(context, permissions)) {
  43.             o = joinPoint.proceed();
  44.         } else {
  45.             Intent intent = new Intent();
  46.             intent.setClass(context, PermissionActivity.class);
  47.             intent.putExtra("permissions", permissions);
  48.             intent.putExtra("requestcode", requestCode);
  49.             context.startActivity(intent);
  50.         }
  51.         return o;
  52.     }
  53.     private boolean checkPermission(Context context, String permission) {
  54.         if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
  55.             return true;
  56.         }
  57.         return false;
  58.     }
  59.     private boolean checkPermissions(Context context, String[] permissions) {
  60.         for(String permission : permissions) {
  61.             if (!checkPermission(context, permission)) {
  62.                 return false;
  63.             }
  64.         }
  65.         return true;
  66.     }
  67. }
复制代码
如许@Permission就被切点劫持了,然后方法就会跑到切面aProceedingJoinPoint。然后获取上下文Context,把权限哀求交给一个透明的Activity来做。做完之后判断效果,用户是同意了还是拒绝了还是曲线了。同意了直接执行point.proceed(),其他方式则通过Activity或者fragment获取带注解的方法,反射执行即可。
三,配置注解 

  1. package com.example.myapplication;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Target(ElementType.METHOD)
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface Permission {
  9.     String[] value();
  10.     int requestCode() default 1;
  11. }
复制代码
 
四,通过空白Activity完成真正的权限申请 

  1. package com.example.myapplication;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.content.pm.PackageManager;
  5. import android.os.Bundle;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import androidx.annotation.NonNull;
  9. import androidx.annotation.Nullable;
  10. import androidx.core.app.ActivityCompat;
  11. import androidx.core.content.ContextCompat;
  12. public class PermissionActivity extends Activity {
  13.     private String[] permissions;
  14.     private int requestCode;
  15.     @Override
  16.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  17.         super.onCreate(savedInstanceState);
  18.         Intent intent = getIntent();
  19.         permissions = intent.getStringArrayExtra("permissions");
  20.         requestCode = intent.getIntExtra("requestcode", 0);
  21.         setContentView(R.layout.activity_permission);
  22.         if (permissions != null && permissions.length > 0) {
  23.             requestPermission(permissions);
  24.         }
  25.     }
  26.     private void requestPermission(String[] permissions) {
  27.         List<String> failure = new ArrayList<>();
  28.         for (String permission : permissions) {
  29.             if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
  30.                 failure.add(permission);
  31.             }
  32.         }
  33.         if (failure.size() == 0) {
  34.             requestPermissionSuccess();
  35.             return;
  36.         }
  37.         ActivityCompat.requestPermissions(this, failure.toArray(new String[]{}), requestCode);
  38.     }
  39.     @Override
  40.     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  41.         
  42.         if (requestCode == this.requestCode) {
  43.             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  44.                 requestPermissionSuccess();
  45.             } else {
  46.                 boolean alwaysHidePermission = false;
  47.                 for (int i = 0; i < grantResults.length; i++) {
  48.                     if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
  49.                         //判断是否勾选禁止后不再询问
  50.                         boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]);
  51.                         if (!showRequestPermission) {
  52.                             alwaysHidePermission = true;
  53.                         }
  54.                     }
  55.                 }
  56.                 requestPermissionFailed();
  57.             }
  58.         }
  59.         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  60.     }
  61.     private void requestPermissionSuccess() {
  62.         setResult(RESULT_OK);
  63.         finish();
  64.     }
  65.     private void requestPermissionFailed() {
  66.         setResult(RESULT_CANCELED);
  67.         finish();
  68.     }
  69. }
复制代码
五,引入依赖配置 

  1. apply plugin: 'com.android.application'
  2. buildscript {
  3.     repositories {
  4.         mavenCentral()
  5.     }
  6.     dependencies {
  7.         classpath 'org.aspectj:aspectjtools:1.8.9'
  8.         classpath 'org.aspectj:aspectjweaver:1.8.9'
  9.     }
  10. }
  11. android {
  12.     compileSdkVersion 29
  13.     buildToolsVersion "29.0.2"
  14.     defaultConfig {
  15.         applicationId "com.netease.premissionstudy"
  16.         minSdkVersion 19
  17.         targetSdkVersion 29
  18.         versionCode 1
  19.         versionName "1.0"
  20.         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  21.     }
  22.     buildTypes {
  23.         release {
  24.             minifyEnabled false
  25.             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  26.         }
  27.     }
  28. }
  29. dependencies {
  30.     implementation fileTree(dir: 'libs', include: ['*.jar'])
  31.     implementation 'androidx.appcompat:appcompat:1.1.0'
  32.     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
  33.     testImplementation 'junit:junit:4.12'
  34.     androidTestImplementation 'androidx.test.ext:junit:1.1.1'
  35.     androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
  36.     implementation 'org.aspectj:aspectjrt:1.8.13'
  37. }
  38. import org.aspectj.bridge.IMessage
  39. import org.aspectj.bridge.MessageHandler
  40. import org.aspectj.tools.ajc.Main
  41. final def log = project.logger
  42. final def variants = project.android.applicationVariants
  43. variants.all { variant ->
  44.     if (!variant.buildType.isDebuggable()) {
  45.         log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
  46.         return;
  47.     }
  48.     JavaCompile javaCompile = variant.javaCompile
  49.     javaCompile.doLast {
  50.         String[] args = ["-showWeaveInfo",
  51.                          "-1.8",
  52.                          "-inpath", javaCompile.destinationDir.toString(),
  53.                          "-aspectpath", javaCompile.classpath.asPath,
  54.                          "-d", javaCompile.destinationDir.toString(),
  55.                          "-classpath", javaCompile.classpath.asPath,
  56.                          "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
  57.         log.debug "ajc args: " + Arrays.toString(args)
  58.         MessageHandler handler = new MessageHandler(true);
  59.         new Main().run(args, handler);
  60.         for (IMessage message : handler.getMessages(null, true)) {
  61.             switch (message.getKind()) {
  62.                 case IMessage.ABORT:
  63.                 case IMessage.ERROR:
  64.                 case IMessage.FAIL:
  65.                     log.error message.message, message.thrown
  66.                     break;
  67.                 case IMessage.WARNING:
  68.                     log.warn message.message, message.thrown
  69.                     break;
  70.                 case IMessage.INFO:
  71.                     log.info message.message, message.thrown
  72.                     break;
  73.                 case IMessage.DEBUG:
  74.                     log.debug message.message, message.thrown
  75.                     break;
  76.             }
  77.         }
  78.     }
  79. }
复制代码
  1. // Top-level build file where you can add configuration options common to all sub-projects/modules.
  2. buildscript {
  3.     repositories {
  4.         google()
  5.         jcenter()
  6.         
  7.     }
  8.     dependencies {
  9.         classpath 'com.android.tools.build:gradle:3.5.2'
  10.         classpath 'org.aspectj:aspectjtools:1.8.9'
  11.         classpath 'org.aspectj:aspectjweaver:1.8.9'
  12.         // NOTE: Do not place your application dependencies here; they belong
  13.         // in the individual module build.gradle files
  14.     }
  15. }
  16. allprojects {
  17.     repositories {
  18.         google()
  19.         jcenter()
  20.         
  21.     }
  22. }
  23. task clean(type: Delete) {
  24.     delete rootProject.buildDir
  25. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4