build.gradle (Project) 和 build.gradle (Module) 的区别是什么?

解读

在国内面试中,这道题几乎必问,因为它直接考察候选人是否真正“跑通过”一个 Android 工程。很多简历写着“熟悉 Gradle”,却说不清两个文件谁管“整个房子”谁管“单间”。面试官想听到的是:

  1. 作用域——Project 级决定“整个工程”的共性配置,Module 级决定“当前模块”的私有配置;
  2. 执行时机——Project 级脚本最先被 evaluate,Module 级脚本在 configure 阶段被逐个调用;
  3. 内容差异——仓库地址、插件版本、全局依赖版本、发布 Nexus 账号、签名信息放在 Project 级;targetSdk、applicationId、buildTypes、productFlavors、dependencies 放在 Module 级;
  4. 继承与覆盖——Module 级可直接引用 Project 级 ext 属性,也可通过 project.rootProject 反向读取,但反之不行;
  5. 国内特色——国内项目往往把 Maven 私服、华为/腾讯/阿里镜像、隐私合规插件、热修插件、AAR 上传脚本全部收敛到 Project 级,Module 级只保留业务依赖,方便 200+ 子模块一键维护。

知识点

  1. Gradle 生命周期:initialization → configuration → execution,Project 级脚本在 configuration 前段统一执行。
  2. allprojects{}subprojects{}buildscript{} 三大代码块只在 Project 级生效;android{}dependencies{} 只能在 Module 级出现。
  3. ext 属性机制:Project 级定义 ext.compileSdk = 34,Module 级通过 rootProject.ext.compileSdk 读取,实现“单点改版本号”。
  4. 插件声明:Project 级 plugins { id 'com.android.application' version '8.2.0' apply false } 仅声明版本,Module 级 plugins { id 'com.android.application' } 真正应用。
  5. 国内多渠道打包:Project 级通过 pluginManagement { repositories { maven { url 'https://maven.aliyun.com/repository/public' } } } 统一换源,Module 级只写 implementation 'com.squareup.okhttp3:okhttp:4.12.0' 即可。
  6. 签名与隐私:国内上架华为、OPPO、VIVO、小米、应用宝 5 大商店,签名配置放在 Module 级,但签名密码通过 Project 级 local.properties 或 CI 环境变量注入,避免提交明文。
  7. 编译优化:Project 级开启 org.gradle.jvmargs=-Xmx8g -XX:+UseParallelGC,Module 级开启 buildTypes.release.minifyEnabled true,分工明确。

答案

build.gradle(Project 级,位于根目录)负责“整个工程”的共性配置:声明 Gradle 插件版本、配置所有模块共享的仓库地址(Google、MavenCentral、国内阿里镜像)、通过 ext 属性统一定义 compileSdk、minSdk、targetSdk、依赖版本号,以及配置 Nexus 上传账号、CI 全局签名信息等。
build.gradle(Module 级,位于 app、library、biz_xxx 等模块目录)负责“当前模块”的私有配置:应用具体插件(com.android.application / library / kotlin-android)、声明 applicationId、配置 buildTypes、productFlavors、compileOptions、kotlinOptions、dependencies 以及模块自身的混淆规则、资源分包、lintOptions 等。
一句话:Project 级管“全家”,Module 级管“自己”;Project 级先执行,Module 级后执行,Module 级可通过 rootProject 读取 Project 级属性,实现版本统一管理。

拓展思考

  1. 在大型 Monorepo 场景下,国内头部 App 往往把 200+ 业务模块拆成独立 repo,再通过 includeBuild 组合成复合构建。此时 Project 级脚本演变为 build-logic convention plugin,用 Kotlin DSL 写成 android-application.gradle.kts,统一固化编译参数,Module 级只剩 plugins { id("android-application") },实现“脚本即插件”的极致复用。
  2. 国内合规要求 2024 年起必须适配 targetSdk 34,且禁止读取已安装应用列表。可把 targetSdk 定义在 Project 级 ext,通过 GitLab CI 定时任务 MR 自动升级,再触发全模块回归,避免“每个业务自己改”导致的漏改。
  3. 隐私沙盒、PI 接口限制导致广告 SDK 需要单独模块隔离。可将广告模块声明为 com.android.library,在 Module 级关闭 minifyEnabled,在 Project 级统一开启 R8 fullMode,其他业务模块开启,实现“部分模块不混淆”的精细控制。