复合构建 (Composite Builds)
源:Gradle 官方文档 - Composite Builds
复合构建允许将独立的 Gradle 项目包含到当前构建中,解决 buildSrc 的缓存问题。
复合构建概念
什么是复合构建
复合构建:将一个或多个独立的 Gradle 项目作为"包含构建"(Included Build)引入到主项目中。
核心API:includeBuild()
build-logic 项目的完整配置流程
首先展示完整的项目布局,再逐个说明每个文件的作用,确保用户知道应该在哪里写代码。
完整项目结构
MyApp/
├── build-logic/ ← 构建逻辑项目
│ ├── convention/ ← 约定插件模块
│ │ ├── build.gradle.kts ← 插件模块的构建脚本
│ │ └── src/main/kotlin/ ← 插件代码存放位置
│ │ ├── AndroidLibraryConventionPlugin.kt
│ │ └── AndroidApplicationConventionPlugin.kt
│ ├── settings.gradle.kts ← build-logic 的 settings
│ └── build.gradle.kts ← (可选)根构建脚本
├── app/ ← 应用模块
│ └── build.gradle.kts ← 使用插件
├── core/ ← 核心库模块
│ └── build.gradle.kts ← 使用插件
├── settings.gradle.kts ← 主项目 settings(引入 build-logic)
└── build.gradle.kts ← 主项目根构建脚本buildSrc vs 复合构建
buildSrc 方案
结构:
project/
├── buildSrc/ ← 特殊目录,自动识别
│ ├── build.gradle.kts
│ └── src/main/kotlin/
│ └── Plugins.kt
├── app/
└── core/优点:
- 简单,无需配置
- 自动识别
缺点:
- ❌ 修改 buildSrc 导致所有模块缓存失效
- ❌ 编译性能差
- ❌ 难以跨项目共享
- ❌ 无法发布到 Maven
缓存问题示意:
修改 buildSrc/Plugins.kt
↓
buildSrc 重新编译
↓
所有模块配置缓存失效
↓
:app、:core、:feature-* 全部重新配置
↓
构建时间大幅增加复合构建方案
结构:
project/
├── build-logic/ ← 独立项目
│ ├── convention/
│ │ ├── build.gradle.kts
│ │ └── src/main/kotlin/
│ └── settings.gradle.kts
├── app/
└── settings.gradle.kts ← includeBuild("build-logic")优点:
- ✅ 独立缓存,不影响主项目
- ✅ 构建性能好
- ✅ 可跨项目共享
- ✅ 可发布到 Maven
- ✅ IDE 支持更好
缓存示意:
修改 build-logic/convention/Plugins.kt
↓
仅 build-logic 重新编译
↓
主项目配置缓存保留
↓
构建时间几乎不变配置复合构建
第一步:创建 build-logic 项目
目录结构:
build-logic/
├── convention/
│ ├── build.gradle.kts
│ └── src/main/kotlin/
│ └── AndroidLibraryConventionPlugin.kt
└── settings.gradle.kts第二步:配置 build-logic/settings.gradle.kts
kotlin
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
include(":convention")说明:
versionCatalogs:引用主项目的 Version Cataloginclude(":convention"):包含 convention 模块
第三步:配置 build-logic/convention/build.gradle.kts
kotlin
plugins {
`kotlin-dsl`
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
}
gradlePlugin {
plugins {
register("androidLibrary") {
id = "my.android.library"
implementationClass = "AndroidLibraryConventionPlugin"
}
}
}说明:
kotlin-dsl:支持 Kotlin DSLcompileOnly:编译时依赖 AGP 和 Kotlin 插件gradlePlugin:注册插件
第四步:主项目 settings.gradle.kts
kotlin
pluginManagement {
includeBuild("build-logic") // ← 关键:引入 build-logic
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
rootProject.name = "MyApp"
include(":app")
include(":core")第五步:使用插件
app/build.gradle.kts:
kotlin
plugins {
id("my.android.library") // 使用 build-logic 中的插件
}
dependencies {
implementation(libs.androidx.core.ktx)
}依赖替换
替换已发布的依赖
场景:本地开发插件,替换 Maven 上的版本。
kotlin
// settings.gradle.kts
includeBuild("../my-gradle-plugin") {
dependencySubstitution {
substitute(module("com.example:my-plugin")).using(project(":"))
}
}使用:
kotlin
// build.gradle.kts
plugins {
id("com.example.my-plugin") version "1.0.0" // 实际使用本地版本
}多项目复合构建
引入多个构建
kotlin
// settings.gradle.kts
includeBuild("build-logic") // 构建逻辑
includeBuild("../shared-library") // 共享库
includeBuild("../gradle-plugins") // 通用插件复合构建间的依赖
kotlin
// build-logic/convention/build.gradle.kts
dependencies {
implementation("com.company:shared-utils:1.0.0") // 来自 shared-library
}实战案例
案例1:标准 build-logic 结构
build-logic/
├── convention/
│ ├── build.gradle.kts
│ └── src/main/kotlin/
│ ├── AndroidApplicationConventionPlugin.kt
│ ├── AndroidLibraryConventionPlugin.kt
│ ├── AndroidComposeConventionPlugin.kt
│ └── utils/
│ ├── KotlinAndroid.kt
│ └── ProjectExtensions.kt
└── settings.gradle.ktsbuild-logic/settings.gradle.kts:
kotlin
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
include(":convention")build-logic/convention/build.gradle.kts:
kotlin
plugins {
`kotlin-dsl`
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.ksp.gradlePlugin)
}
gradlePlugin {
plugins {
register("androidApplication") {
id = "my.android.application"
implementationClass = "AndroidApplicationConventionPlugin"
}
register("androidLibrary") {
id = "my.android.library"
implementationClass = "AndroidLibraryConventionPlugin"
}
register("androidCompose") {
id = "my.android.compose"
implementationClass = "AndroidComposeConventionPlugin"
}
}
}案例2:跨项目共享插件
项目 A:
workspace/
├── my-gradle-plugins/ ← 插件项目
│ ├── convention/
│ └── settings.gradle.kts
└── project-a/
├── settings.gradle.kts ← includeBuild("../my-gradle-plugins")
└── app/项目 B:
workspace/
├── my-gradle-plugins/ ← 同一个插件项目
└── project-b/
├── settings.gradle.kts ← includeBuild("../my-gradle-plugins")
└── app/最佳实践
使用 includeBuild 而非 buildSrc:
kotlin
// settings.gradle.kts
pluginManagement {
includeBuild("build-logic")
}项目命名:
build-logic/ # 推荐:清晰明确
gradle/build-logic/ # 也可以Version Catalog 共享:
kotlin
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}模块化:
build-logic/
├── convention/ # 约定插件
├── settings/ # Settings 插件
└── publishing/ # 发布插件IDE 支持:
- 可以单独打开 build-logic 项目
- 独立开发和测试插件
- 更好的代码补全
CI 优化:
yaml
# GitHub Actions
- name: Cache Gradle
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
build-logic/.gradle