Settings插件必须用Kotlin DSL(settings.gradle.kts)编写,本质是封装复用的配置逻辑为函数或类并在顶层调用,不支持传统插件机制;唯一稳定复用方式是apply(from = "...")加载外部.kts脚本。

Settings插件必须用 Kotlin DSL(settings.gradle.kts)编写
Gradle 的 Settings 对象本身不支持传统插件机制——你不能像对 Project 那样 apply 一个二进制插件到 Settings。所谓“Settings 插件”,本质是把复用的 settings 配置逻辑封装成 Kotlin 函数或类,然后在 settings.gradle.kts 中调用。
这意味着:没有 Plugin 接口实现、没有 apply(plugin = "...")、也不支持通过 plugins { id("...") } 块引入。
- 所有逻辑必须在
settings.gradle.kts文件顶层作用域或其导入的 Kotlin 脚本中执行 - 若想复用,只能靠
includeBuild引入另一个构建(含settings.gradle.kts),或通过apply(from = "...")加载外部.kts脚本 - Gradle 8.4+ 支持
settings.pluginManagement { ... },但仅用于配置插件仓库和版本,不等于“应用插件”
apply(from = "...") 是最实用的复用方式
把通用 settings 逻辑(如统一 include 模块、动态解析目录结构、设置构建缓存地址)抽成独立 .kts 文件,再用 apply(from = "...") 加载——这是目前最稳定、最易调试的做法。
示例:gradle/settings-conventions.kts
rootProject.name = "my-project"
include(":app", ":core", ":data")
enableFeaturePreview("VERSION_CATALOGS")
在 settings.gradle.kts 中:
pluginManagement { repositories { mavenCentral() } }
apply(from = "$rootDir/gradle/settings-conventions.kts")
- 路径必须是绝对路径或相对于
settings.gradle.kts的相对路径;$rootDir在apply(from = ...)中不可用,得写成file("../gradle/settings-conventions.kts")或用layout.projectDirectory.file("gradle/settings-conventions.kts") - 被加载脚本里不能用
plugins { ... }块(会报错 “Plugin management is not allowed in script plugins”),只能用pluginManagement { ... }或纯 Settings API 调用 - 多个
apply(from = ...)顺序敏感:后加载的可以覆盖前者的rootProject.name或include结果
别试图在 init.gradle 或 gradle.properties 里改 Settings 行为
有人想绕过 settings.gradle.kts 直接干预 Settings 生命周期,比如在 init.gradle 里 hook Settings 实例——这行不通。Init 脚本运行时 Settings 尚未创建,且 Gradle 明确禁止在 init 阶段修改 project / settings 结构。
-
gradle.properties只能提供键值对,无法执行逻辑;org.gradle.configuration-cache=true这类开关有效,但不能用来驱动include判断 - 自定义
GradleLauncher或嵌入式调用属于 Gradle 内部 API,不稳定、无文档、跨版本极易崩 - 如果真需要条件化 include(例如按环境变量开关模块),唯一可靠方式是在
settings.gradle.kts顶层用System.getenv("CI") != null或providers.systemProperty(...)判断,再决定是否include
Settings 脚本里访问不到 Project API,也别混用 buildSrc
settings.gradle.kts 的闭包接收者是 Settings,不是 Project。你不能在这里调用 dependencies { ... }、tasks.register(...),也不能直接引用 buildSrc 里的类——因为 buildSrc 是为 Project 构建服务的,在 Settings 阶段尚未编译、不可见。
- 如果需要类型安全的工具函数(比如解析 TOML 版本目录),得把它们打包成独立 jar,放在
gradle/libs下,再用pluginManagement { classpath(...)注册,最后通过settings.classLoader.loadClass(...)反射调用(不推荐,太重) - 更轻量做法:用 Kotlin 标准库原生能力,比如
File("...").walk().find { it.name == "build.gradle.kts" }动态发现子项目,避免硬编码include - 所有涉及 I/O 的操作(读文件、查环境变量)必须在
settings.gradle.kts顶层执行,不能包裹在gradle.beforeProject等回调里——那些回调只对 Project 生效
真正难的不是写代码,是厘清 Gradle 构建生命周期里 Settings 阶段的边界:它只有一次解析机会,没有缓存重用,不能依赖 Project 层产物,任何“想让它更像 build.gradle”的尝试都会撞墙。











