2. 多模块项目Gradle配置结构:root build.gradle、settings.gradle、模块级build.gradle职责、统一配置方式

多模块项目(Multi‑Module)的 Gradle 配置由三个层级的文件共同完成:settings.gradle 声明模块边界,root build.gradle 控制全局行为,模块级 build.gradle 描述各自构建逻辑。理解每个文件的职责边界,并掌握统一配置方法,是避免版本冲突、缓存同步失败的基础。

2.1 配置文件职责对比

文件执行阶段核心职责常见误区
settings.gradleInitialization声明模块列表、配置仓库、版本目录在 settings.gradle 中编写依赖声明
root build.gradleConfiguration全局插件版本、仓库、allprojects/subprojects 公共配置将模块特有逻辑放在 root 中
模块 build.gradleConfiguration模块专属依赖、插件应用、自定义任务重复书写同一组配置(如 Kotlin 版本)

2.2 settings.gradle:模块声明与仓库管理

在 Initialization 阶段解析,它决定了哪些模块被纳入构建树。典型结构:

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "MyApp"
include(":app")
include(":library:core")
include(":library:network")

注意:pluginManagement 和 dependencyResolutionManagement 只能出现在 settings.gradle 中,不能在其他文件重复定义。使用 include() 而非扁平字符串,避免路径混淆。

2.3 root build.gradle:全局配置与插件声明

根模块(:)的 build.gradle 通常只放置项目级插件版本声明和公共配置:

plugins {
    id("com.android.application") version "8.2.0" apply false
    id("com.android.library") version "8.2.0" apply false
    id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}

allprojects {
    // 所有项目(包括根模块)共享的配置
    configurations.configureEach {
        resolutionStrategy.cacheChangingModulesFor(0, "seconds")
    }
}

subprojects {
    // 只影响子模块
    apply(plugin = "org.jetbrains.kotlin.android")
    android {
        compileSdk = 34
        defaultConfig.minSdk = 21
    }
}

警告:allprojects 和 subprojects 块会泄漏到所有子模块,容易造成构建缓存冲突。AGP 8.0+ 推荐使用 Convention Plugins 替代。

2.4 模块级 build.gradle:模块专属配置

每个子模块的 build.gradle 聚焦于自身职责:

plugins {
    id("com.android.library")
    id("kotlin-android")
    id("maven-publish")
}

android {
    namespace = "com.example.library.core"
    compileSdk = 34
    defaultConfig {
        minSdk = 21
    }
}

dependencies {
    implementation(project(":library:network"))
    implementation("com.google.android.material:material:1.11.0")
}

遵循单一职责:模块级只配置本模块所必需的参数,例如不同的 minSdk、buildTypes 或特有的依赖。全局统一参数通过 Convention Plugins 注入。

多模块 Gradle 配置文件结构 settings.gradle root build.gradle :app (application) :library:core :library:network Convention Plugin 图例 实线:配置依赖 虚线:统一注入 根级配置文件 模块配置文件

2.5 统一配置方式

为了避免在每个模块的 build.gradle 中重复写相同的 compileSdk、minSdk、targetSdk 等参数,Gradle 提供了多种统一配置手段。推荐优先级从高到低:

  1. Convention Plugins(推荐) — 将共享配置抽取为 Gradle Plugin,在模块中直接 apply
  2. subprojects / allprojects 块 — 简单项目可用,但会污染所有模块的命名空间
  3. 版本目录(Version Catalog) — 统一依赖版本,但参数仍需单独写
  4. 自定义 Extension — 更灵活,适合复杂参数传递
实践建议:在 AGP 8.x 中,官方已不推荐使用 subprojects 块直接设置 android 参数。改为创建 build-logic 模块(Convention Plugin),并在其中定义 android-common.gradle.kts,然后通过 apply(from = rootProject.file("..")) 或直接作为 included build 引入。

2.6 常见错误与调试

错误场景根因解决方案
Project with path ':library' not foundsettings.gradle 未 include 该模块检查 include() 名称是否匹配路径
Cannot set 'compileSdk' on a null object子模块未应用 android library plugin在模块级或 Convention Plugin 中先 apply 插件
Build cache invalidated on every changeallprojects 块中修改了不可缓存属性将配置移至 Convention Plugin,并使用 @CacheableTask 优化
Dependency on 'classpath' configuration is deprecated在 root build.gradle 中使用过时的 classpath 声明全部迁移到 plugins 块 + apply false
关键警告:统一配置时切勿将 dependencies 块放在 subprojects 或 allprojects 中。这会导致所有模块强制依赖相同库,且无法灵活处理变体(如仅 debug 模块需要特定依赖)。正确的做法是在每个模块的 build.gradle 中按需声明依赖,或通过 Convention Plugin 传递条件性依赖。

2.7 调试配置结构

遇到配置不生效或同步失败时,依次执行以下命令定位问题:

# 查看最终模块的完整配置
./gradlew :app:dependencies --configuration debugRuntimeClasspath

# 输出项目树
./gradlew projects

# 查看模块的 Gradle 属性
./gradlew :app:properties | grep -E "compileSdk|minSdk"

同时,在 Android Studio 的 Gradle Sync 窗口中可以展开每个模块的 build/ 目录,查看中间生成的 build script 缓存文件,这是验证 Convention Plugin 是否正确注入的有效手段。