如何在Android项目中将 Kapt 插件迁移到 KSP 插件.
什么是 Kapt?
Kapt(Kotlin 注释处理工具) 允许你在 Kotlin 代码中使用 Java 注释处理器, 即使这些处理器并不支持 Kotlin. 这是通过从 Kotlin 文件中生成 Java 存根来实现的, 处理器可以读取这些存根. 生成存根是一项昂贵的操作, 对构建速度有很大影响.
Kapt 现在处于维护模式, 建议尽可能从 kapt 迁移到 KSP. 在大多数情况下, 这种迁移只需要修改项目的构建配置即可.
为什么要用 Kapt?
kapt的一些用法:
- 注解处理器参数
使用 arguments {}
块将参数传递给注解处理器:
Kotlin
kapt {
arguments {
arg("key", "value")
}
}
- 支持Gradle构建缓存
kapt 注解处理任务默认缓存在 Gradle 中. 然而, 注解处理器运行的任意代码不一定会将任务输入转化为输出, 可能会访问和修改 Gradle 未跟踪的文件等. 如果在构建过程中使用的注解处理器无法正确缓存, 可以在构建脚本中添加以下几行, 完全禁用 kapt 的缓存, 以避免 kapt 任务的缓存命中错误:
kapt { useBuildCache = false }
- 将 Kapt 当作注解处理器使用
我们像这样使用Room.
Kotlin
implementation "androidx.room:room-ktx:2.5.2"
kapt("androidx.room:room-compiler:2.5.2")
我们像这样使用Dagger-hilt.
Kotlin
implementation "com.google.dagger:hilt-android:2.44.2"
kapt "com.google.dagger:hilt-android-compiler:2.44.2"
kapt "androidx.hilt:hilt-compiler:1.0.0"
什么是KSP?
KSP(Kotlin符号处理)是 Kotlin 优先的 kapt 替代品. KSP 直接分析 Kotlin 代码, 速度最多可提高 2 倍. 它还能更好地理解 Kotlin 的语言结构.
在迁移过程中, 你可以在项目中同时运行 kapt 和 KSP, 而且迁移可以逐模块, 逐库进行.
注意: 如果模块中仍有 kapt 处理器, 则仍会在该模块中生成存根. 这就意味着, 只有当模块中所有使用 kapt 的地方都被移除后, 性能才会得到大幅提升.
为什么KSP会更快?
Kotlin 注解处理工具(KAPT)与 Java 的注解处理基础架构协同工作, 使大多数 Java 语言注解处理器都能在 Kotlin 中开箱即用. 为此, KAPT 将 Kotlin 代码编译成 Java 存根, 保留 Java 注解处理器所关心的信息. 不过创建这些存根的成本很高, 这意味着编译器必须多次解析程序中的所有符号(一次用于生成存根, 另一次用于实际编译).
KSP 允许注解处理器直接在 Kotlin 中读取和分析源程序和资源, 而不需要依赖 Java 注解处理基础架构. 这不仅显著提高了构建速度(Room 的Kotlin 测试应用程序可提高 2 倍), 还意味着 KSP 可用于 Kotlin/Native 和 Kotlin/JS 等非 Android 和非 JVM 环境.
用法与Kapt相同.
迁移步骤:
以下是迁移步骤概览:
- 检查你使用的库是否支持 KSP.
- 在项目中添加 KSP 插件.
- 用 KSP 替换注解处理器.
- 移除 kapt 插件.
1. 检查所用库是否支持 KSP
在开始之前, 请检查你与 kapt 一起使用的库是否已经支持 KSP. 许多流行的库(包括Glide, Room和Moshi)都支持 KSP, 还有一些库(如Dagger)正在添加支持.
你可以查看文档中的支持库列表, 或参考你正在使用的库的文档和问题跟踪器.
注意: 数据绑定虽然不是传统意义上的依赖库, 但它也使用注解处理器来提供功能, 而KSP不计划支持数据绑定. 你可以将数据绑定的使用隔离到单独的模块中, 从而减轻 kapt 对你构建的影响.
2. 在项目中添加 KSP 插件
首先, 在顶层的 build.gradle.kts
文件中声明 KSP 插件. 确保选择的 KSP 版本与项目的 Kotlin 版本一致. 你可以在KSP GitHub 页面上找到版本列表.
Kotlin
plugins {
id("com.google.devtools.ksp") version "1.8.22-1.0.11" apply false
}
然后, 在模块级的 build.gradle.kts
文件中启用 KSP:
Kotlin
plugins {
id("com.google.devtools.ksp")
}
3. 用 KSP 替换注解处理器
启用 KSP 后, 就可以开始用 KSP 替换 kapt 的使用. 对于绝大多数库来说, 这只需在依赖关系声明中将 kapt 改为 ksp 即可, 因为它们会将注解处理器和 KSP 处理器放在同一个工件中.
注意: 某些库(如Glide)可能还需要将依赖关系更改为不同的构件. 请务必查阅它们的文档.
Kotlin
dependencies {
kapt("androidx.room:room-compiler:2.5.2") // remove this dependency
ksp("androidx.room:room-compiler:2.5.2") // add this dependency
}
转移到 KSP 后, 同步并构建你的项目, 看看它是否仍能正常运行.
需要注意的一些常见问题:
- 某些库不支持 kapt 和 KSP 完全相同的功能. 如果你的代码在迁移后出现问题, 请查看库的文档.
- 与 kapt 相比, KSP 拥有更准确的 Kotlin 类型信息(例如, 关于可空性), 这意味着 KSP 处理器可以更精确地确定类型要求. 除了更新编译文件外, 这可能还需要对源代码进行一些修正.
- 如果以前向注解处理器传递参数, 现在可能需要向 KSP 传递这些参数. 请注意, 参数的格式在 kapt 和 KSP 之间可能有所不同. 请参阅KSP 文档, 并查阅你正在使用的库的文档以了解更多信息.
4. 删除 kapt 插件
如果模块中不再包含与kapt
相关的依赖项, 请删除 kapt 插件.
注意: Data Binding 也需要在模块中启用 kapt. 在使用数据绑定的模块中, 不能移除 kapt.
如果它是在插件块中声明的:
Kotlin
plugins {
id("org.jetbrains.kotlin.kapt")
}
如果是使用 Groovy 的应用插件语法:
arduino
apply plugin: 'kotlin-kapt'
你还应删除任何与 kapt 相关的残留配置, 例如:
Kotlin
kapt {
correctErrorTypes = true
useBuildCache = true
}