build.gradle (Project) 和 build.gradle (Module) 的区别是什么?
解读
在国内面试中,这道题几乎必问,因为它直接考察候选人是否真正“跑通过”一个 Android 工程。很多简历写着“熟悉 Gradle”,却说不清两个文件谁管“整个房子”谁管“单间”。面试官想听到的是:
- 作用域——Project 级决定“整个工程”的共性配置,Module 级决定“当前模块”的私有配置;
- 执行时机——Project 级脚本最先被 evaluate,Module 级脚本在 configure 阶段被逐个调用;
- 内容差异——仓库地址、插件版本、全局依赖版本、发布 Nexus 账号、签名信息放在 Project 级;targetSdk、applicationId、buildTypes、productFlavors、dependencies 放在 Module 级;
- 继承与覆盖——Module 级可直接引用 Project 级 ext 属性,也可通过
project.rootProject反向读取,但反之不行; - 国内特色——国内项目往往把 Maven 私服、华为/腾讯/阿里镜像、隐私合规插件、热修插件、AAR 上传脚本全部收敛到 Project 级,Module 级只保留业务依赖,方便 200+ 子模块一键维护。
知识点
- Gradle 生命周期:initialization → configuration → execution,Project 级脚本在 configuration 前段统一执行。
allprojects{}、subprojects{}、buildscript{}三大代码块只在 Project 级生效;android{}、dependencies{}只能在 Module 级出现。ext属性机制:Project 级定义ext.compileSdk = 34,Module 级通过rootProject.ext.compileSdk读取,实现“单点改版本号”。- 插件声明:Project 级
plugins { id 'com.android.application' version '8.2.0' apply false }仅声明版本,Module 级plugins { id 'com.android.application' }真正应用。 - 国内多渠道打包:Project 级通过
pluginManagement { repositories { maven { url 'https://maven.aliyun.com/repository/public' } } }统一换源,Module 级只写implementation 'com.squareup.okhttp3:okhttp:4.12.0'即可。 - 签名与隐私:国内上架华为、OPPO、VIVO、小米、应用宝 5 大商店,签名配置放在 Module 级,但签名密码通过 Project 级
local.properties或 CI 环境变量注入,避免提交明文。 - 编译优化: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 级属性,实现版本统一管理。
拓展思考
- 在大型 Monorepo 场景下,国内头部 App 往往把 200+ 业务模块拆成独立 repo,再通过
includeBuild组合成复合构建。此时 Project 级脚本演变为build-logicconvention plugin,用 Kotlin DSL 写成android-application.gradle.kts,统一固化编译参数,Module 级只剩plugins { id("android-application") },实现“脚本即插件”的极致复用。 - 国内合规要求 2024 年起必须适配 targetSdk 34,且禁止读取已安装应用列表。可把 targetSdk 定义在 Project 级
ext,通过 GitLab CI 定时任务 MR 自动升级,再触发全模块回归,避免“每个业务自己改”导致的漏改。 - 隐私沙盒、PI 接口限制导致广告 SDK 需要单独模块隔离。可将广告模块声明为
com.android.library,在 Module 级关闭minifyEnabled,在 Project 级统一开启 R8 fullMode,其他业务模块开启,实现“部分模块不混淆”的精细控制。