android - 如何每次使用 gradle 制作方面编织 kotlin 代码
问题描述
我正在做一些 AOP 研究并使用 gradle + aspectJ 来编织我的代码。所以我做了一些演示,将aspectJtools添加到顶级build.gradle。
dependencies {
...
classpath 'org.aspectj:aspectjtools:1.9.5'
}
并在 app/build.gradle 中添加任务以编织代码:
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
}
}
}
}
然后我添加我的方面,如:
@Aspect
public class AspectInCommon extends BaseAspect {
@Pointcut("execution(* com.example.cheng.test.MainActivityKt.on**(..))")
public void kotlinMainOn() {
}
@After("kotlinMainOn()")
public void hookKotlinMain(JoinPoint joinPoint) throws Throwable {
log(joinPoint.getSignature().toLongString());
}
...
}
我的 MainActivity 看起来像:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
}
}
通过这种方式,我确实将方面融入了我的代码。这是一些输出: 它第一次工作正常,直到我再次单击调试底部,然后所有输出都不再被触发。然后经过几次测试,我发现如果我的文件之一在 kotlin 中,它只会在干净构建后编织。所以我尝试将 mainActivity 和 aspect 文件更改为 java 或 kotlin。这是测试结果:
MainActivity language Aspect language Weave results
Java Java Weave every time
Java Kotlin Weave after clean build *
Kotlin Java Weave after clean build
Kotlin Kotlin Weave after clean build
*:我将方面文件放在子模块中,它在干净构建后的第二次构建中崩溃。错误信息是:
java.lang.NoSuchMethodError: No static method aspectOf()
我想知道如何每次都制作方面编织 kotlin 代码,而不是在干净构建后只制作一次,因为我真实项目的大多数代码都是基于 kotlin 的。不简单地使用插件是完美的。非常感谢。
解决方案
我既不使用 Gradle(而是 Maven)也不使用 Kotlin,但我对多种 JVM 语言或多个编译步骤的经验是,在单独的模块中执行每个编译步骤是有意义的。
- 所以你可以有一个 Java + Kotlin 应用程序类模块,用普通的 Java/Kotlin 编译器编译它。
- 然后你有一个用 AspectJ 编译器编译的方面模块。
- 最后,有一个使用 AspectJ 进行二进制编织的模块,使用 inpath 上的第一个模块和 aspect 路径上的第二个模块。
这使得构建更简单,更稳定。其他优点是您拥有一个原始的、未编织的应用程序模块和一个方面增强的模块。根据具体情况,您可以在应用程序中使用前者或后者,例如,如果您编织不应该总是使用的调试或跟踪方面。最后但并非最不重要的一点是,单独的方面模块使方面库可能可重用。
推荐阅读
- scheduling - 如何按顺序编写用于调度的约束
- r - 在 R 中查找特定行
- sql - 当不过滤右侧时,T-SQL 从左连接的右侧删除空值
- highcharts - 类别标签的Highcharts自定义格式/着色
- android - 如何为XMPP android的聊天节实现OMEMO加密
- visual-studio - 无法在现代 Windows 上启动 Visual Studio 2008 dll
- css - 使用 Grid 和 Flexbox 的响应式页面问题
- java - 在 Python 中使用 X509 证书签署信封,结果与 Java 相同
- download - 如何优化从 Google Colab 下载数据集的时间?
- csv - 使用 Tensorflow 和 Keras 训练高光谱数据