IT评测·应用市场-qidao123.com技术社区
标题:
Android怎样通过aspectj打造一个无侵入式动态权限申请框架
[打印本页]
作者:
美食家大橙子
时间:
前天 22:46
标题:
Android怎样通过aspectj打造一个无侵入式动态权限申请框架
目次
一,背景
二,通过Aspectj管理全部的注解
三,配置注解
四,通过空白Activity完成真正的权限申请
五,引入依赖配置
一,背景
在Activity或者fragment中,写在几个方法写一些解释,用来表现权限申请成功,申请失败,多次拒绝。同时需要无侵入式,让业务开发者尽大概的少些代码,把焦点的业务逻辑下沉到框架层
二,通过Aspectj管理全部的注解
它的作用就是劫持被解释的方法的执行。我在ASPECT中配置拦截@permission解释的方法。先做判断。如果没有相识过Aspect的话,AOP面向切面编程,各人应该听说过,它可以用来配置事务、做日记、权限验证、在用户哀求时做一些处置惩罚等等。而用@Aspect做一个切面,就可以直接实现。
package com.example.myapplication;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
@Aspect
public class PermissionAspect {
//com.example.myapplication
private static final String POINTCUT_METHOD = "execution(@com.example.myapplication.Permission * *(..))";
@Pointcut(POINTCUT_METHOD)
public void methodAnnotatedWithPermission() {
}
@Around("methodAnnotatedWithPermission()")
public Object permissionMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Permission permission = method.getAnnotation(Permission.class);
String[] permissions = permission.value();
int requestCode = permission.requestCode();
Object object = joinPoint.getThis();
Context context = null;
if (object instanceof Activity) {
context = (Activity) object;
} else if (object instanceof FragmentActivity) {
context = (FragmentActivity) object;
} else if (object instanceof Fragment) {
context = ((Fragment) object).getContext();
} else if (object instanceof Service) {
context = (Service) object;
}
Object o = null;
if (checkPermissions(context, permissions)) {
o = joinPoint.proceed();
} else {
Intent intent = new Intent();
intent.setClass(context, PermissionActivity.class);
intent.putExtra("permissions", permissions);
intent.putExtra("requestcode", requestCode);
context.startActivity(intent);
}
return o;
}
private boolean checkPermission(Context context, String permission) {
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
return true;
}
return false;
}
private boolean checkPermissions(Context context, String[] permissions) {
for(String permission : permissions) {
if (!checkPermission(context, permission)) {
return false;
}
}
return true;
}
}
复制代码
如许@Permission就被切点劫持了,然后方法就会跑到切面aProceedingJoinPoint。然后获取上下文Context,把权限哀求交给一个透明的Activity来做。做完之后判断效果,用户是同意了还是拒绝了还是曲线了。同意了直接执行
point.proceed()
,其他方式则通过Activity或者fragment获取带注解的方法,反射执行即可。
三,配置注解
package com.example.myapplication;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
String[] value();
int requestCode() default 1;
}
复制代码
四,通过空白Activity完成真正的权限申请
package com.example.myapplication;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class PermissionActivity extends Activity {
private String[] permissions;
private int requestCode;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
permissions = intent.getStringArrayExtra("permissions");
requestCode = intent.getIntExtra("requestcode", 0);
setContentView(R.layout.activity_permission);
if (permissions != null && permissions.length > 0) {
requestPermission(permissions);
}
}
private void requestPermission(String[] permissions) {
List<String> failure = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
failure.add(permission);
}
}
if (failure.size() == 0) {
requestPermissionSuccess();
return;
}
ActivityCompat.requestPermissions(this, failure.toArray(new String[]{}), requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == this.requestCode) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
requestPermissionSuccess();
} else {
boolean alwaysHidePermission = false;
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
//判断是否勾选禁止后不再询问
boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]);
if (!showRequestPermission) {
alwaysHidePermission = true;
}
}
}
requestPermissionFailed();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
private void requestPermissionSuccess() {
setResult(RESULT_OK);
finish();
}
private void requestPermissionFailed() {
setResult(RESULT_CANCELED);
finish();
}
}
复制代码
五,引入依赖配置
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.netease.premissionstudy"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'org.aspectj:aspectjrt:1.8.13'
}
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return;
}
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.8",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)
MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler);
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break;
case IMessage.WARNING:
log.warn message.message, message.thrown
break;
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.debug message.message, message.thrown
break;
}
}
}
}
复制代码
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4