4. 根 build.gradle 与模块 build.gradle 职责拆分

根 build.gradle 与模块 build.gradle 职责拆分 学习卡片

为什么需要拆分根脚本与模块脚本

多模块 Android 工程里,根 build.gradle 与各模块 build.gradle 承担的是两类不同职责。根脚本负责“全局约定”:插件版本、公共插件是否统一应用、子模块通用配置;模块脚本负责“局部差异”:本模块是 com.android.application 还是 com.android.library、自己的 namespace、编译版本、依赖坐标。若把公共插件和版本变量散落在每个模块里,就会出现同一版本号写多份、升级时漏改、模块间配置漂移的问题。

根 build.gradle(全局约定) plugins { id 'com.android.application' version '8.2.0' apply false } ext { compileSdk = 34; minSdk = 24 } subprojects { repositories { google(); mavenCentral() } } 模块 build.gradle(局部差异) plugins { id 'com.android.application' } android { namespace 'com.demo.app' } dependencies { implementation project(':core') } 继承/约束 下沉前:公共配置散落在各模块 app/build.gradle → plugins { id 'com.android.application' version '8.2.0' } core/build.gradle → plugins { id 'com.android.library' version '8.2.0' } feature/build.gradle → plugins { id 'com.android.library' version '8.2.0' } 下沉后:版本只在根脚本声明一次 根 build.gradle → plugins { id 'com.android.application' version '8.2.0' apply false } 各模块 → plugins { id 'com.android.application' }(不写版本)

拆分后的文件结构

以三模块工程为例,拆分后的职责边界如下:

文件职责关键内容
根 build.gradle全局插件版本、公共 SDK 变量、子模块通用仓库plugins 块带 apply false、ext 变量、subprojects 块
app/build.gradle应用模块专属配置com.android.application、namespace、applicationId、模块依赖
core/build.gradle库模块专属配置com.android.library、namespace、api/implementation 依赖
feature/build.gradle库模块专属配置com.android.library、namespace、模块依赖

根 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
}

ext {
    compileSdkVersion = 34
    minSdkVersion = 24
    targetSdkVersion = 34
}

subprojects {
    repositories {
        google()
        mavenCentral()
    }
}

关键点:apply false 表示只在根脚本解析插件版本,不在此处应用插件;ext 中的变量可被所有子模块通过 rootProject.ext.compileSdkVersion 读取;subprojects 块统一为所有子模块添加仓库,避免每个模块重复写 repositories。

模块 build.gradle 写法

// app/build.gradle
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    namespace 'com.demo.app'
    compileSdk rootProject.ext.compileSdkVersion

    defaultConfig {
        applicationId 'com.demo.app'
        minSdk rootProject.ext.minSdkVersion
        targetSdk rootProject.ext.targetSdkVersion
        versionCode 1
        versionName '1.0'
    }
}

dependencies {
    implementation project(':core')
    implementation project(':feature')
}
// core/build.gradle
plugins {
    id 'com.android.library'
    id 'org.jetbrains.kotlin.android'
}

android {
    namespace 'com.demo.core'
    compileSdk rootProject.ext.compileSdkVersion

    defaultConfig {
        minSdk rootProject.ext.minSdkVersion
    }
}

dependencies {
    api 'androidx.core:core-ktx:1.12.0'
}

模块脚本不再写插件版本号,SDK 版本统一从 rootProject.ext 读取。这样升级 AGP 或 compileSdk 时只需改根脚本一处。

验证构建结果一致

拆分完成后,用以下命令验证配置是否生效且构建结果与拆分前一致:

# 1. 查看各模块解析到的插件版本
./gradlew :app:dependencies --configuration classpath

# 2. 查看编译 SDK 是否统一
./gradlew :app:properties | grep -i compileSdk

# 3. 执行完整构建
./gradlew clean assembleDebug

# 4. 对比拆分前后 APK 的 versionCode / versionName
./gradlew :app:assembleDebug
aapt dump badging app/build/outputs/apk/debug/app-debug.apk | head -1
验证通过条件:assembleDebug 成功;aapt dump badging 输出的 versionCode 与 versionName 与拆分前一致;各模块 compileSdk 均为 34。若出现 Could not find method compileSdk(),检查根脚本 ext 变量名与模块引用名是否拼写一致。

常见问题与排查

  • Plugin [id: 'com.android.application'] was not found:根脚本 plugins 块缺少版本声明,或 settings.gradle 的 pluginManagement 未配置仓库。
  • 模块中 rootProject.ext.compileSdkVersion 报 null:根脚本 ext 块在 subprojects 之后才执行,需确保 ext 块位于文件顶部。
  • 子模块重复应用插件导致 Cannot add task 'clean' as a task with that name already exists:检查是否在根脚本误用了 apply plugin 而非 apply false。