自定义Gradle plugin Java AnnotationProcessor 和 Kotlin Kapt 断点调试

Posted 薛瑄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义Gradle plugin Java AnnotationProcessor 和 Kotlin Kapt 断点调试相关的知识,希望对你有一定的参考价值。

前言

Java 的注解处理器AnnotationProcessor 和 Kotlin的注解处理器 Kapt 会在编译期,根据代码的注解,生成代码。对处理注解的代码进行调试,可以更快的定位问题。那么就需要在编译期调试代码

网上很多文章,只是介绍了如何操作,但是没有说明原理的,导致不明所以,操作时候出现问题就不知从何下手

1、首先我们先对调试器进行一些简单的了解,再去介绍 调试注解处理器AnnotationProcessor就会清晰明了,懂了原理,操作基本就是一次学会。

2、Java和Kotlin 对注解的处理,使用的工具不一样。

  • Java 是使用AnnotationProcessor来根据注解来生成代码,
  • Kotlin 是使用Kapt 来根据注解来生成代码,

所以他们debug调试的方法不太一样,后面会详细介绍

一、调试编译期的Java代码

Gradle 是运行在JVM上的,在初始化的时候会加载一些必要的库,所以第一次运行会有些慢。为了避免每次运行都运行慢的问题,Gradle 推出了一个长时间存活的进程——Daemon (关于Gradle Daemon的官方文档)Gradle 调用AnnotationProcessor 是在Daemon 进程

下面以bufferknife为例,来演示如何调试注解处理器AnnotationProcessor

1.1、创建远程调试

点击Run——>Edit configurations,会打开如下图的界面,点击“+”号,选择Remote

  • 在1填入名称:Annotation,其他的都不用修改

  • Host和Port 不用修改

  • 复制2处的命令,这是远程调试的jvm命令,在其他运行的进程中,配置这条命令。关于这些参数的说明可以参考这篇博文

1.2 配置Gradle任务

首先打开AS右边的Gradle小窗口,然后打开butterknife-integration-test->other目录,找到compileDebugJavaWithJavac,右键选择,如下图所示:

把在上面复制的命令粘贴到下图VM options的位置:

VM options 是配置Daemon 进程的VM 参数,

注意需要把suspend=n 改为 suspend=y,如下 这么做是为了保证compileDebugJavaWithJavac运行前会一直等待调试器的连接。

-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005

为什么要配置上面这两个东西呢?

  1. 因为调试注解处理器是在compile时期执行的,所以要配置compileDebugJavaWithJavac的任务
  2. 添加那条命令是让compileDebugJavaWithJavac任务可以attach到远程调试

这样当该任务执行的时候,就可以进行调试

如果你更习惯使用命令行来执行gradle task,直接在命令中加入参数,就可以了。例如下面的3.2

1.3 开始调试

在开始调试前,注意一定一定要清掉注解处理器生成的文件,在build文件夹里的文件。可以执行clean project来清理。
因为如果注解所在文件不发生任何改变的话,编译时注解处理器只会运行一遍。不清理再次执行,就直接build完成了

1.3.1 首先在代码中设置断点

1.3.2 执行compileDebugJavaWithJavac

因为该任务运行在Daemon 进程 中,也对Daemon 进程配置了远程调试,所以执行该任务(它是个调试任务),会等待远程调试器,所以debug远程调试器就可以断点了

1.3.2 执行远程调试器

选择已创建好的Remote调试——Annotation,启动调试

这时compileDebugJavaWithJavac,附加到远程调试器,开始正常执行,就会在代码指定断点处停下来

注意:之前提到过,AnnotationProcessor生成文件一次后,如果注解没有发生改变,接不会再次执行。所以再次调试的时候一定记得clean project

二、在编译期调试Kotlin代码

在开始介绍方法前,先把原理梳理一下,那么后面操作就会一目了然

Kotlin代码处理注解,使用的是Kapt,而不是AnnotationProcessor

在使用Gradle构建工具,对kapt的处理,不是在Daemon 进程,而是在kotlin.daemon 进程中,所以需要对kotlin.daemon 的jvm参数进行配置,而不能像上面那样配置

2.1 、创建远程调试

和 1.1、创建远程调试 的方法一模一样

2.2 、配置kotlin.daemon 进程JVM参数

添加 kapt.use.worker.api=true 到 Gradle properties

Since 1.3.20 kapt.use.worker.api runs annotation processing in the main Gradle process.

执行命令


./gradlew --no-daemon -Dorg.gradle.debug=true -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n" :app:clean :app:assemble

参数解释:

--no-daemon 不使用daemon进程

-Dorg.gradle.debug=true 开启一个新的Gradle process,用于远程调试

-Dkotlin.daemon.jvm.options 对kotlin.daemon进程设置远程调试参数

2.3、执行远程调试器

我后来又重新调试时
环境:

kotlin 1.3.31
android studio 3.6.1
gradle 4.10.3
com.android.tools.build:gradle:3.2.0

如果没有开启远程调试,执行的任务会卡住,此时开启远程调试,就可以继续运行。

成功断点是这样子的

这里延伸 一下,kapt是先生成stub (一个java类),然后根据生成的java类的注解,去生成代码 ,如下图

三、调试自定义的Gradle plugin

调试自定义的Gradle plugin,需要先发布插件,可以发布到本地。然后通过远程调试的方式,来断点调试

3.1 、创建远程调试

和 1.1、创建远程调试 的方法一模一样

3.2 、执行命令

在主module上 执行命令

./gradlew --no-daemon -Dorg.gradle.debug=true -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n" :app:clean :app:assemble

此时命令行会等待的这里

3.3 、 执行远程调试器

选择已创建好的Remote调试——xw-plugin-debug,启动调试

3.4、此时命令行 停留在这里

如果 像上图一样,命令行停留在这里不动,这时再次点击第3.3步 中的远程调试按钮,选择stop and rerun,稍等几秒即可成功断点

拓展

如果你的项目是java kotlin 混合的,以执行任务语言为主。

例如:
app 是java,lib 是kotlin,那么用java的注解调试方式,lib中的注解也是可以断点调试的
如果app,lib 都是kotlin,则只能使用kotlin的注解调试方式

请点赞、收藏,感谢大家的支持,有任何疑问可在评论区回复

参考:

如何调试编译时注解处理器AnnotationProcessor
编译时注解处理方
Annotation Processor
调试Annotation Processor编译时注解器
如何debug自定义AbstractProcessor
Android APT 编译期进入debug模式

Annotation Processing with Kapt and Gradle
Debug Annotation Processor Kapt
Can’t Debug an Annotation Processor when using kapt and gradle
Android Studio中kapt调试annotation processor的一些注意事项

该文章的内容,我之前调试时有这样的情况,需要在执行某个任务,快速启动远程调试,但是后来并没有这样的问题
Annotation Processing with Kapt and Gradle

Debug annotation processor in Kotlin
Gradle插件开发系列之gradle插件调试方法

以上是关于自定义Gradle plugin Java AnnotationProcessor 和 Kotlin Kapt 断点调试的主要内容,如果未能解决你的问题,请参考以下文章

自定义Gradle plugin Java AnnotationProcessor 和 Kotlin Kapt 断点调试

Android Gradle 插件Gradle 自定义 Plugin 插件 ⑤ ( 自定义插件中获定义方法 | 在插件中创建 Gradle 任务 | 代码示例 )

Android Gradle 插件Gradle 自定义 Plugin 插件 ③ ( 自定义插件作用 | Android Gradle 插件的扩展 | 自定义 Extension 扩展 )

Android Gradle 插件Gradle 自定义 Plugin 插件 ⑦ ( 自定义 Gradle 插件导入方式 | buildSrc 插件导入 | 构建脚本中自定义插件 | 独立文件 )

Android Gradle 插件Gradle 自定义 Plugin 插件 ⑦ ( 自定义 Gradle 插件导入方式 | buildSrc 插件导入 | 构建脚本中自定义插件 | 独立文件 )

Android Gradle 插件Gradle 自定义 Plugin 插件 ④ ( 为自定义 Gradle 插件的扩展配置扩展 | 在自定义插件中获取扩展属性 )