Android 引入AspectJ的记录

Android 引入 AspectJ进行AOP开发的记录。

在不试用插件时,引入AspectJ到android工程

1. 在项目gradle引入插件: 


    dependencies {
        ...
        classpath 'org.aspectj:aspectjtools:1.9.5'
        ...
    }

2. 在创建aspect文件的包引入


dependencies {
    ...
    implementation 'org.aspectj:aspectjrt:1.9.5'
    ...
}

并在同gradle文件中,加入


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 ->
    JavaCompile javaCompile
    if (variant.hasProperty('javaCompileProvider')) {
        //android gradle 3.3.0 +
        javaCompile = variant.javaCompileProvider.get()
    } else {
        javaCompile = variant.javaCompile
    }
    def buildType = variant.buildType.name

    javaCompile.doLast {

        MessageHandler handler = new MessageHandler(true)

        String[] javaArgs = [
                "-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)
        ]

        new Main().run(javaArgs, handler)

        String[] kotlinArgs = [
                "-showWeaveInfo",
                "-1.8",
                "-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
                "-aspectpath", javaCompile.classpath.asPath,
                "-d", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
                "-classpath", javaCompile.classpath.asPath,
                "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
        ]

        new Main().run(kotlinArgs, 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:
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break
            }
        }
    }
}

这样就成功引入AspectJ工具了,下一步编写Aspect文件。

3. 先实现自己的业务逻辑

package com.example.cheng.test;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.widget.TextView;

import com.example.common.DisplayMetricsUtil;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivityJava extends AppCompatActivity {

    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView text = findViewById(R.id.text);
        text.measure(0, 0);
        text.setText("text width: " + DisplayMetricsUtil.px2dp(this, text.getMeasuredWidth()));
    }
}

4. 再在同module下实现aspect文件 

package com.example.cheng.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MainActivityAspectJava extends BaseAspect {

    @Pointcut("execution(* com.example.cheng.test.MainActivityJava.on*(..))")
    public void mainPointCut() {
    }

    @After("mainPointCut()")
    public void hookMain(JoinPoint joinPoint) throws Throwable {
        log("java::" + joinPoint.getSignature().toLongString());
    }

    @Pointcut("call(* com.example.common.DisplayMetricsUtil.*(..))")
    public void displayPointCut() {
    }

    @After("displayPointCut()")
    public void hookDisplay(JoinPoint joinPoint) throws Throwable {
        log("java::" + joinPoint.getSignature().toLongString());
    }
}

输出效果: 

 

补充记录:

1. 因为kotlin文件编译出的.class文件路径与java不同,所以需要额外为aspect tool指定kotlin的路径。


        String[] kotlinArgs = [
                "-showWeaveInfo",
                "-1.8",
                "-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
                "-aspectpath", javaCompile.classpath.asPath,
                "-d", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
                "-classpath", javaCompile.classpath.asPath,
                "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
        ]
        new Main().run(kotlinArgs, handler)

 

待解决问题:

1. kotlin每次都需要clean build

2. 如何跨module实现aop weave,即在一个包中,可以通过pointcut切入其他module中的方法及其调用。

3. Java写的业务逻辑,kotlin的aspect文件能够对其织入;Kotlin写的业务逻辑,Java的Aspect文件不能对其织入。

你可能感兴趣的:(android,AOP,AspectJ)