预编译脚本插件是Gradle 6.0+推荐的轻量级插件形式,需置于gradle/plugins/目录下,以plugins{id("plugin.xxx")}方式应用,不可用apply plugin:,且不可在顶层直接访问project。

预编译脚本插件(Precompiled Script Plugins)是 Gradle 6.0+ 引入的推荐方式,替代了旧版的“构建脚本插件”(即直接写在 build.gradle 里的类),它用 .gradle.kts 或 .gradle 文件定义逻辑,经 Gradle 自动编译为二进制插件,具备类型安全、IDE 支持好、可复用等优势。它不是 buildSrc,也不是独立插件项目,而是以脚本文件为单元、放在固定位置、被自动识别和编译的轻量级插件形式。
脚本文件必须放在 gradle/plugins/ 目录下
Gradle 只会在项目根目录的 gradle/plugins/ 子路径中查找并编译预编译脚本插件。其他位置(如 buildSrc、src/main/kotlin 或任意自定义路径)都不会被识别为预编译插件。
- 正确路径示例:
gradle/plugins/my-convention.gradle.kts - 错误路径示例:
buildSrc/src/main/kotlin/MyPlugin.kt(这是buildSrc插件,非预编译脚本插件) - 错误路径示例:
gradle/my-convention.gradle.kts(少了一级plugins/)
Gradle 会为每个 .gradle.kts 文件生成一个唯一的插件 ID,格式为 plugin.<filename_without_extension></filename_without_extension>,比如 my-convention.gradle.kts 对应插件 ID plugin.my-convention。
apply 时不能用字符串 ID,必须用 plugins { id(...) } 块
预编译脚本插件只能通过 plugins { id "plugin.my-convention" }(Groovy)或 plugins { id("plugin.my-convention") }(KTS)方式应用,不支持 apply plugin: "plugin.my-convention" 这种旧式写法——后者会报错 Plugin with id 'plugin.my-convention' not found,因为 Gradle 的插件解析器在传统 apply plugin: 模式下根本不会扫描 gradle/plugins/ 目录。
- ✅ 正确:
plugins { id("plugin.my-convention") } - ❌ 错误:
apply plugin: "plugin.my-convention"
- ⚠️ 注意:该
plugins块必须出现在构建脚本顶部(KTS 中甚至要求在任何import之前),否则会触发解析失败
脚本内不能直接访问 project,要用 gradle.includedBuilds 或 settings 扩展点
预编译脚本插件本质是 Settings Plugin 或 Project Plugin,其作用域取决于你把它用在哪。如果你把它应用在 settings.gradle.kts 中,它就运行在 Settings 上下文;如果应用在 build.gradle.kts 中,则运行在 Project 上下文。但关键点是:你**不能在脚本顶层直接调用 project.version = "1.0" 这类语句**,因为此时 project 尚未初始化(会报 Cannot access project without initialization)。
- ✅ 正确做法(在
build.gradle.kts中应用时):plugins { id("plugin.my-convention") } // 在 afterEvaluate 或 tasks.register 中操作 project</afterEvaluate> - ✅ 更推荐做法:把配置逻辑封装进
configureEach或withType,例如:tasks.withType<Jar> { archiveBaseName.set("mylib") } - ⚠️ 容易忽略:预编译脚本插件默认没有
gradleApi()或localGroovy()依赖,所以不能像buildSrc那样随意使用 Gradle 内部 API;所有对外暴露的类型必须是公开、稳定的公共 API
真正容易卡住的地方,是以为“写个 .gradle.kts 就算完成了”,结果发现 IDE 不提示、plugins { id(...) } 找不到、或者一写 project. 就报空指针——其实问题往往出在路径不对、应用方式错、或过早访问未就绪的构建对象上。预编译脚本插件轻量,但边界清晰,越早按它的规则来,越少掉坑里。


















