Skip to content

复合构建 (Composite Builds)

源:Gradle 官方文档 - Composite Builds

复合构建允许将独立的 Gradle 项目包含到当前构建中,解决 buildSrc 的缓存问题。

复合构建概念

什么是复合构建

复合构建:将一个或多个独立的 Gradle 项目作为"包含构建"(Included Build)引入到主项目中。

核心APIincludeBuild()

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 Catalog
  • include(":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 DSL
  • compileOnly:编译时依赖 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.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")

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