注:该文章已过时,新版本见:【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
- at the top of your
App/build.gradleadd:buildscript { ext.aspectjVersion = '1.9.1' dependencies { classpath "org.aspectj:aspectjtools:$aspectjVersion" } }
- At the bottom of your
App/build.gradleadd: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) {
}
}
}
}
