当你的 Gradle 项目不断增长时,你可能希望将其拆分成多个子项目,以提高模块化、可维护性和并行执行能力。

本指南解释了如何将单项目构建转换为多项目构建

为什么使用多项目构建?

单项目构建在一个 build.gradle(.kts) 文件中管理所有源代码和依赖项。

相比之下,多项目构建包含:

  • 一个根项目,其中包含共享配置和依赖项,定义在 settings.gradle(.kts) 文件中。

  • 多个子项目,每个子项目都有自己的 build.gradle(.kts) 文件、依赖项和任务。

步骤 1:项目结构

让我们从一个典型的单项目设置开始,这个设置由 gradle init 命令创建

root
├── settings.gradle(.kts) (1)
└── app (2)
    ├── build.gradle(.kts)
    └── src/
1 定义根项目设置
2 单个应用模块

或者,你的单项目可能看起来像这样

app (root) (1)
├── build.gradle(.kts)
├── settings.gradle(.kts)
└── src/
1 项目根目录,同时也是应用模块
如果你的项目是这样的结构,在开始之前,请将 app 文件夹嵌套在一个新的 root 文件夹内。

将其转换为多项目构建后,结构将看起来像这样

root
├── settings.gradle(.kts) (1)
├── app (2)
│   ├── build.gradle(.kts)
│   └── src/
└── library (3)
    ├── build.gradle(.kts)
    └── src/
1 定义子项目
2 原始的应用模块,现在是一个子项目
3 一个新的库模块

步骤 2:创建一个或多个新的子项目

现在你可以在 root 目录中创建额外的项目目录。它们都将成为根项目的子项目。

为了继续我们的例子,我们创建一个名为 library 的新子项目

cd root
mkdir library

确保原始项目 (app) 与新的 library 子项目处于同一级别

root
├── app (1)
│   └── some files
└── library (2)
1 原始应用模块
2 新创建的子项目

将源文件移动到相应的文件夹中。

在我们的例子中,可重用代码被移动到 library 子项目

root
├── app (1)
│   └── src/
└── library (2)
    └── src/
1 应用模块,包含其自身的源代码
2 新的库模块,用于存储可重用代码

步骤 3:更新 settings.gradle(.kts)

确保 settings.gradle(.kts) 位于根目录

root
├── settings.gradle(.kts) (1)
├── app (2)
│   └── src/
└── library (3)
    └── src/
1 整个构建的单个设置文件
2 应用模块
3 新的库模块

修改 settings.gradle(.kts) 文件以包含新的子项目。

在我们的例子中,我们将 library 添加到 include

settings.gradle.kts
rootProject.name = "root"
include("app", "library")
settings.gradle
rootProject.name = "root"
include("app", "library")

不应该有其他设置文件.

步骤 4:为每个子项目创建 build.gradle(.kts) 文件

每个子项目必须有自己的 build.gradle(.kts) 文件

root
├── settings.gradle(.kts) (1)
├── app (2)
│   ├── build.gradle(.kts) (3)
│   └── src/
└── library (4)
    ├── build.gradle(.kts) (5)
    └── src/
1 定义子项目
2 应用子项目
3 定义 app 构建
4 库子项目
5 定义 library 构建

app 的构建文件应该与原始构建文件非常相似。它包含构建 app 子项目所需的所有依赖项和配置。

现在,它还依赖于 library 子项目

app/build.gradle.kts
plugins {
    application
    id("org.jetbrains.kotlin.plugin.serialization") // Now the plugin is applied
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.google.guava:guava:33.3.1-jre")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
    implementation(project(":library")) // Uses the library module
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

application {
    mainClass = "org.example.App"
}
app/build.gradle
plugins {
    id('application')
    id("org.jetbrains.kotlin.plugin.serialization") // Now the plugin is applied
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.google.guava:guava:33.3.1-jre")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
    implementation(project(":library")) // Uses the library module
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

application {
    mainClass = "org.example.App"
}

library 的构建文件应该是新的。它包含构建 library 子项目所需的所有依赖项和配置。

library/build.gradle.kts
plugins {
    id("java-library")
    id("org.jetbrains.kotlin.plugin.serialization") // Now the plugin is applied
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.apache.commons:commons-lang3:3.17.0")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}
library/build.gradle
plugins {
    id("java-library")
    id("org.jetbrains.kotlin.plugin.serialization") // Now the plugin is applied
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.apache.commons:commons-lang3:3.17.0")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}

步骤 5:修改或删除根项目的 build.gradle(.kts)

根项目中的构建文件是可选的

root
├── settings.gradle(.kts) (1)
├── build.gradle(.kts) (2)
├── app (3)
│   ├── build.gradle(.kts)
│   └── src/
└── library (4)
    ├── build.gradle(.kts)
    └── src/
1 定义子项目
2 可选(用于共享配置)
3 应用模块
4 新的库模块

如果你需要配置共享仓库和设置,可以使用根项目的 build.gradle(.kts) 文件。

build.gradle.kts
plugins {
    id("org.jetbrains.kotlin.plugin.serialization") version "1.9.21" apply false
}

subprojects {
    repositories {
        mavenCentral()
    }
}
build.gradle
plugins {
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.21' apply false
}

subprojects {
    repositories {
        mavenCentral()
    }
}

你可以回顾一下名为 org.jetbrains.kotlin.plugin.serialization 的第三方常用插件是如何在每个构建文件中应用的。

然而,共享逻辑应该使用约定插件 (convention plugins)来处理,而不是使用根构建文件。

总结

这个过程可以无限重复以添加更多子项目

root
├── settings.gradle(.kts) (1)
├── app (2)
│   ├── build.gradle(.kts)
│   └── src/
├── library-a (3)
│   ├── build.gradle(.kts)
│   └── src/
├── library-b (4)
│   ├── build.gradle(.kts)
│   └── src/
└── library-c (5)
    ├── build.gradle(.kts)
    └── src/
1 定义子项目
2 应用模块
3 一个共享库模块
4 另一个库模块
5 又一个库模块

通过遵循这些步骤,你可以模块化你的项目,提高可维护性,并实现并行执行。

如果你想让你的某个库成为一个独立的构建,你应该考虑使用复合构建 (Composite Builds)(即 included builds)。