必须先应用 kotlin-kapt 插件,否则 kapt 配置块被忽略,注解处理器(如 room-compiler)不生效,编译时可能静默跳过或报“annotation processors must be explicitly declared now”;插件需在 build.gradle.kts 中按顺序声明:id("com.android.application")、kotlin("android")、kotlin("kapt"),且依赖必须用 kapt 声明而非 implementation 或 annotationprocessor。

必须先应用 kotlin-kapt 插件
不加这个插件,kapt 配置块会被 Gradle 忽略,所有注解处理器依赖(比如 room-compiler、dagger-compiler)都不会生效,编译时可能静默跳过或报 Error: Annotation processors must be explicitly declared now。
在模块级 build.gradle.kts 中,确保插件顺序包含它:
plugins {
id("com.android.application")
kotlin("android")
kotlin("kapt") // ← 这一行不能少
}
注意:kotlin("kapt") 是 Kotlin DSL 写法;Groovy 下是 apply plugin: "kotlin-kapt"。两者不可混用,否则插件加载失败。
kapt 依赖必须用 kapt 声明,不能用 implementation 或 annotationProcessor
常见错误是把编译器插件当成普通库引入,例如写成 implementation("androidx.room:room-compiler:2.6.0") —— 这会导致 Room 注解不生成代码,运行时直接 ClassNotFoundException。
正确写法分两类:
- 纯 Kotlin 项目(无 Android):只用
kapt - Android 项目:按源集区分,如测试需用
kaptAndroidTest
示例(Android 模块):
dependencies {
implementation("androidx.room:room-runtime:2.6.0")
kapt("androidx.room:room-compiler:2.6.0") // ← 必须用 kapt
// 测试中也需要处理注解时
kaptAndroidTest("com.google.dagger:dagger-compiler:2.48")
}
传参数给注解处理器要用 kapt { arguments { arg(...) } }
像 ARouter、AndroidAnnotations、Room 等都需要传配置参数(如 AROUTER_MODULE_NAME),但 Android Gradle Plugin 3.2+ 后,android { javaCompileOptions { annotationProcessorOptions { ... } } } 已被弃用,Kotlin DSL 下必须走 kapt 块。
错误写法(旧式、Gradle 会警告或忽略):
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments["AROUTER_MODULE_NAME"] = project.name
}
}
}
}
正确写法(Kotlin DSL 推荐):
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.name)
arg("room.schemaDirectory", file("$projectDir/schemas"))
}
}
注意:arg() 只接受字符串键值对;若需传文件路径,应确保路径存在且可读,否则处理器可能静默失败。
容易漏掉的兼容性开关:Gradle 构建缓存和 Worker API
默认情况下,kapt 任务不参与 Gradle 构建缓存,也不并行执行——这意味着每次 clean build 都重跑全部注解处理,尤其在多 module 项目里拖慢明显。
两个关键优化项要手动开启:
- 在
gradle.properties中加:kapt.use.worker.api=true(要求 Gradle ≥ 4.10.3,Kotlin ≥ 1.2.60) - 同样在
gradle.properties中加:org.gradle.caching=true,并在模块build.gradle.kts的kapt块里写:useBuildCache.set(true)
漏掉前者,kapt 任务永远单线程;漏掉后者,即使开了构建缓存,kapt 仍不会复用结果。这两项不报错,但性能差异极大,且很难从日志里察觉。











