1. 常见注解处理器:apt、kapt、ksp
- apt 全称是“Annotation Processing Tool”,是
javac的一个工具,中文意思为编译时注解处理器。apt可以用来在编译时扫描和处理注解,提取相关信息,然后根据信息来自动的生成一些代码,省去了手动编写。详细可参考:编译时注解处理器(APT)详解
- kapt
apt是javac的一个工具,无法处理kotlin源码中的java注解。为了在kotlin源码中使用java注解,需要一个特殊的注解处理器,于是便有了kapt。kapt先将kotlin源码编译成java源码,然后再使用apt处理注解。即kapt是基于apt的注解处理器。详细可参考:Android编译优化系列-kapt篇
- ksp 全称是"Kotlin Symbol Processing",是
Kotlin官方提供的用于生成代码的编译时注解处理器工具。用于替代kapt的工具,用于简化编译时代码生成的过程。可以理解成kotlin版本的apt。 - 总结
上图描述了几个处理器的处理过程。目前
ksp是kotlin官方推荐的注解处理器,相比kapt具备下面这些优点:- 编译效率更快
kapt处理时,需先把kotlin源码转换成java源码再处理注解。相比之下,ksp可以直接处理kotlin源码,省去中间的转换步骤,效率更高。 - 跨平台
kapt依赖apt,即kapt仅适用于JVM平台。相比之下,ksp是基于kotlin的,而kotlin本身就是跨平台的,所以ksp也具备跨平台的能力。‘ - 更多可以参考:Why KSP
- 编译效率更快
2. kapt迁移至ksp
由于框架的要求等,迁移至ksp的前提是:AGP升级至8、kotlin升级至1.9。
基本的插件引入等,这里就不展开讨论了,详细可参考:Migrate from kapt to KSP。
下面讨论主流框架升级时遇到的问题。
- Dagger
- 官方升级指南 传送门
- 问题
Dagger目前仅做了部分ksp支持,有些注解还不支持。例如下面这个:直接把上面依赖的kapt "com.google.dagger:dagger-android-processor:xxx"kapt替换成ksp会导致报错,因为相关注解还不支持。
- Room
- 官方升级指南 传送门
- 问题
Room支持导出数据库的架构,需要添加如下注解处理器选项:
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation":"$projectDir/schemas".toString(),
"room.incremental":"true"
]
}
}
}
}
在Room切换到ksp后,需要将上述配置改成ksp版本的,如下所示。这部分在官方文档没有提到,我也是遇到崩溃后,经过一番折腾才知道的。
android {
...
defaultConfig {
ksp {
arg("room.schemaLocation", "$projectDir/schemas".toString())
arg("room.incremental", "true")
}
}
}
- Glide
- 官方升级指南 传送门
- 问题 详见:LibraryGlideModule does not work after migrate to ksp
3. 总结
测试了几个项目中的常见场景
| case | kapt | ksp | 优化幅度 |
|---|---|---|---|
| M1 + 增量debug安装(修改底层module) | 37s | 35s | 6% |
| M1 + clean + assembleDbeug | 4m50s | 4m24s | 9% |
| intel + clean + assembleRelease | 15m | 13m | 14% |
几个场景下都会有收益,迁移也是比较简单的,值得一试。
4. 一些疑问
-
同样使用了注解,为啥有的框架不需要通过
kapt "xxxxx"引入注解处理器呢?很多主流框架都使用了注解,注解可以辅助标记信息,使代码更加简单清晰,方便开发者使用框架。这些注解在不同阶段被使用,大致可以分成:编译阶段和运行阶段。
编译阶段 比如
Glide,Glide利用注解处理器,在编译阶段生成模版代码,例如这个文件:/build/generated/ksp/allArchDebug/kotlin/com/bumptech/glide/GeneratedAppGlideModuleImpl.kt。在编译阶段处理注解,就需要引入相关的注解处理器,如:ksp "com.github.bumptech.glide:ksp:$glideVersion"运行阶段 比如
Retrofit,Retrofit则是在程序运行的时候,利用反射提取注解信息,然后动态构建代码。这种就不需要引入相关的注解处理器。 -
annotationProcessor、kapt、ksp的区别
我们可以通过
annotationProcessor "xx"、kapt "xx"、ksp "xx"等方式引入注解处理器。当模块中只包含
java代码时,我们可以使用annotationProcessor "xx";当模块中同时包含java和kotlin代码时,我们需要使用kapt "xx"或ksp "xx"。kapt和ksp会兼容kotlin和java代码。