【Android】在 Android / kotlin 中使用 AspectJ

注:该文章已过时,新版本见:【Android】在 Android / kotlin 中搭建 AspectJ 环境

项目中需要使用到 AOP 的功能,所以总结了一下在 Android 中使用 Aspectj 的方式。以下方案均可以在高等级的 Gradle + Kotlin 中使用,测试环境为 gradle 7.2 + kotlin 1.6.10

一、方案调研

方案1:直接使用 Aspectj

https://stackoverflow.com/questions/44364633/aspectj-doesnt-work-with-kotlin/53320843#53320843

  1. at the top of your App/build.gradle add:
buildscript {
    ext.aspectjVersion = '1.9.1'
    dependencies {
        classpath "org.aspectj:aspectjtools:$aspectjVersion"
    }
}
  1. At the bottom of your App/build.gradle add:
android.applicationVariants.all { variant ->

// add the versionName & versionCode to the apk file name
variant.outputs.all { output ->
    def newPath = outputFileName.replace(".apk", "-${variant.versionName}.${variant.versionCode}.apk")
    outputFileName = new File(outputFileName, newPath)


    def fullName = ""
    output.name.tokenize('-').eachWithIndex { token, index ->
        fullName = fullName + (index == 0 ? token : token.capitalize())
    }

    JavaCompile javaCompile = variant.javaCompiler

    MessageHandler handler = new MessageHandler(true)
    javaCompile.doLast {
        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)]

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

        new Main().run(javaArgs, handler)
        new Main().run(kotlinArgs, handler)

        def log = project.logger
        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
            }
        }
    }
}

方案2:使用 gradle-aspectj-pipeline-plugin

该方案是方案1的封装,只需要引入插件就可以使用,非常方便。

其他方案

另外调研了 Aspectjx,由于作者已经停止维护,所以放弃之。

二、遇到的问题

由于引入 Aspectj 之后,编译(rebuild)会报以下错误:

image.png

所以最后没有使用 Aspectj,采用了其他方案。不知是否有该问题的解决方式?

2023年2月28日更新

以上问题已解决:
针对在Android中引入AspectJ导致clean失败的问题 //www.greatytc.com/p/22cb9e76e9f7?v=1677575161668

采用方案1,且其中的脚本内容修改为如下:

buildscript {
    repositories {
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
        google()
        mavenCentral()
    }

}

// app 和 lib 属性不同
def variants = null
if (project.android.hasProperty("applicationVariants")) {
    variants = project.android.applicationVariants
} else if (project.android.hasProperty("libraryVariants")) {
    variants = project.android.libraryVariants
}

variants.all { variant ->
    variant.outputs.all { output ->
        def fullName = ""
        output.name.tokenize('-').eachWithIndex { token, index ->
            fullName = fullName + (index == 0 ? token : token.capitalize())
        }

        JavaCompile javaCompile = variant.javaCompileProvider.get()
        javaCompile.doLast {
            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)]
            println "ajc javaArgs: " + Arrays.toString(javaArgs)
            String[] kotlinArgs = ["-showWeaveInfo",
                                   "-1.8",
                                   "-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + fullName,
                                   "-aspectpath", javaCompile.classpath.asPath,
                                   "-d", project.buildDir.path + "/tmp/kotlin-classes/" + fullName,
                                   "-classpath", javaCompile.classpath.asPath,
                                   "-bootclasspath", project.android.bootClasspath.join(
                    File.pathSeparator)]
            println "ajc kotlinArgs: " + Arrays.toString(kotlinArgs)

            def wv = configurations.create("weaving")
            dependencies {
                weaving 'org.aspectj:aspectjtools:1.9.8'
            }
            try {
                javaexec {
                    classpath = wv
                    main = "org.aspectj.tools.ajc.Main"
                    args javaArgs
                }
            } catch (Exception e) {
            }
            try {
                javaexec {
                    classpath = wv
                    main = "org.aspectj.tools.ajc.Main"
                    args kotlinArgs
                }
            } catch (Exception e) {
            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容