Gradle Settings API:settings.gradle.kts 详解
说实话,很多 Android 开发者对 settings.gradle.kts 的认知,还停留在「项目入口」这个层面。我以前带团队时发现,不少人甚至不知道这个文件能写逻辑代码。嗯,今天我们就把它彻底讲透。
Settings 文件的前世今生
在 Gradle 4.x 时代,settings.gradle 基本就是个摆设——放几个 include 就完事了。但从 Gradle 6.8 开始,Settings API 被大幅增强,到了 Gradle 7.0+,它已经成了整个构建系统的「控制面板」。
我个人习惯把 settings.gradle.kts 看作项目的「启动配置中心」。它比 build.gradle.kts 执行得更早,能做的事情也更多。
核心功能一:模块管理(include)
最基础的功能,就是声明子模块。但这里有个坑——我见过有人把 include 写成了字符串列表,结果编译报错半天找不到原因。
// 标准写法
include(":app")
include(":library:core")
include(":library:network")
// 也可以一行搞定
include(":app", ":library:core", ":library:network")
// 动态 include —— 这个技巧我常用
file("modules").listFiles()?.forEach { dir ->
if (dir.isDirectory && File(dir, "build.gradle.kts").exists()) {
include(":${dir.name}")
project(":${dir.name}").projectDir = dir
}
}
核心功能二:插件管理(pluginManagement)
这是 Gradle 6.8 引入的重磅特性。以前插件版本散落在各个 build.gradle.kts 里,管理起来简直噩梦。现在统一在 settings.gradle.kts 里声明,爽多了。
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
// 私有仓库 —— 我在公司内部搭建过
maven { url = uri("https://plugins.mycompany.com") }
}
// 版本统一声明
plugins {
id("com.android.application") version "8.2.0"
id("org.jetbrains.kotlin.android") version "1.9.20"
}
// 版本解析策略 —— 解决冲突用的
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == "com.android") {
useVersion("8.2.0")
}
}
}
}
你想想看,如果每个模块都写一遍插件版本,升级时得改多少个文件?有了 pluginManagement,改一处就完事。
核心功能三:依赖版本目录(Version Catalog)
Version Catalog 是 Gradle 7.0 推出的,说白了就是给依赖版本号建个「字典」。我强烈建议所有新项目都用这个。
首先在 gradle/libs.versions.toml 里定义:
[versions]
kotlin = "1.9.20"
compose = "1.5.4"
retrofit = "2.9.0"
[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
retrofit-core = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
然后在 settings.gradle.kts 里启用:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("gradle/libs.versions.toml"))
}
}
}
使用的时候,在 build.gradle.kts 里直接引用:
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.compose.ui)
implementation(libs.retrofit.core)
}
这样做的好处是什么?版本号统一管理,升级时只改一个文件。我曾经在一个 30+ 模块的项目里,把版本升级从半天缩短到了 10 分钟。
核心功能四:includeBuild 与复合构建
includeBuild 是 Gradle 的「大招」。它允许你把另一个 Gradle 项目作为依赖引入。我常用它来引入本地开发的 SDK 或工具库。
// 引入本地构建的插件项目
includeBuild("../my-gradle-plugin")
// 引入本地开发的 SDK
includeBuild("../network-sdk") {
dependencySubstitution {
substitute(module("com.example:network-sdk"))
.using(project(":network-sdk"))
}
}
// 甚至可以引入多个
includeBuild("../shared-lib")
includeBuild("../analytics-sdk")
为什么要用 includeBuild 而不是 include?区别在于:include 是把模块拉进当前项目,includeBuild 是引入一个独立的 Gradle 构建。前者共享同一个构建生命周期,后者各自独立。
- 本地开发 SDK,需要实时调试
- 自定义 Gradle 插件,边开发边测试
- 跨项目共享构建逻辑
知识体系总览
下面这张图,是我梳理的 Settings API 核心脉络:
避坑指南
讲几个我踩过的坑:
- 插件版本冲突:我曾经在
pluginManagement和build.gradle.kts里同时声明了同一个插件但版本不同,结果 Gradle 报错说「ambiguous」。后来统一只在pluginManagement里声明,问题解决。 - Version Catalog 路径:默认路径是
gradle/libs.versions.toml,但如果你改了路径,记得在from(files(...))里写对。我见过有人写成from("libs.versions.toml"),结果死活找不到文件。 - includeBuild 的循环依赖:两个项目互相
includeBuild,Gradle 会直接崩溃。别问我怎么知道的。
总结
settings.gradle.kts 早已不是当年的「小透明」。它承担了模块管理、插件管理、版本目录、复合构建等核心职责。我个人建议,新项目从一开始就把这些配置用好,省得后面重构。
记住一句话:能用 Settings API 解决的问题,就别往 build.gradle.kts 里塞。这样你的项目结构会更清晰,维护成本也更低。
公众号:蓝海资料掘金营,微信deep3321