环境:
android studio版本:4.2.2
android gradle插件版本:3.1.2
参考文档:
android aop(三) AspectJ
AspectJ在Android中的使用
1.配置环境(引入AspectJ插件)
(1)在project的build.gradle中补充如下配置
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}
(2)在实际使用的module的build.gradel补充下面配置
如果module是library, 需要将下面配置中variants变量的赋值替换替换为project.android.libraryVariants,否则会引起报错。
dependencies {
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
// 如果是library, 下面一行替换为final def variants = project.android.libraryVariants
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;
}
}
}
}
2.使用
创建如下切片处理类
@Aspect 用来标志切面的处理类
@Pointcut 标志切点,可以使已经有的类方法,也可以是注解
@Before 切入代码运行在切点代码前,同理还有 @After, @Around等
@Aspect
public class AspectUtil {
@Pointcut("execution(* cn.test.MainActivity.clickView(..))")
public void pointCut() {
}
@Before("pointCut()")
public void testBefore() {
Log.i("Aspect", "testBefore");
}
@Pointcut("execution(@com.test.aspectj.AspectTT * *(..))") // 自定义的注解
public void pointCut2() {
}
@After("pointCut2()")
public void testAfter(JoinPoint point) {
// 切片处理逻辑
Log.i("Aspect", "testAfter");
}
// 切点直接用方法名
@Around("execution(public int cn.test.MainActivity.getUI(int, int))")
public Object testAfterThrow(ProceedingJoinPoint point) {
Object result;
int type = 1;
try {
type = (Integer) point.getArgs()[1];
result = point.proceed();
} catch (Throwable throwable) {
return -1;
}
return result;
}
}
3.结果
写好之后看看运行结果,或者运行之后看看生成的最终class文件,如下图已经插入了目标代码。
4.限制
aspectJ是在编译期对程序代码处理,将目标代码写入到.class文件中,所以不支持对aar和jar中的class文件的插入。
|