系列三:组件化与模块化进阶 | 第9篇 组件化架构从零搭建实战:Gradle 极速配置、编译加速与多环境管控
系列三:组件化与模块化进阶 | 第9篇
组件化架构从零搭建实战:Gradle 极速配置、编译加速与多环境管控
阅读警告
本文为超深度技术长文,预计阅读时长 40-60 分钟,代码量极大。
在第8篇中,我们完成了组件化的物理拆分和路由通信。
但仅仅拆开是不够的。如果你发现拆完后编译反而更慢了,或者打包时各个组件的环境变量乱成一团,那是因为你没有做好Gradle 工程化治理。
这一篇,我们将深入 Android 构建系统的腹地,解决编译速度慢、依赖冲突、多环境混乱、多渠道包体积大等四大核心痛点。
全文包含:Gradle Kotlin DSL 迁移、Version Catalog 统一依赖、Configuration Cache 实战、多环境资源配置、以及美团 VasDolly 极速多渠道打包方案。
1 引子:组件化后的“构建之痛”
很多团队在拆完组件后,会面临一个新的困境:“拆得快,编得慢”。
1.1 症状诊断
- 编译时间不减反增:以前单工程编译 5 分钟,拆成 20 个组件后,编译变成了 15 分钟。因为 Gradle 要处理更多的 Module 依赖解析。
- 依赖地狱:组件 A 用了 Glide 4.12,组件 B 用了 Glide 4.15,组件 C 用了老版本的 Support Library。运行时发生
ClassNotFoundException或Method Not Found。 - 环境混乱:测试同学拿着包说“这是测试环境吗?”,你一看接口地址是正式环境的。因为各个组件里的
BASE_URL没有统一。 - 多渠道打包慢:打 10 个渠道包要 1 个小时,因为要全量编译 10 次。
1.2 企业级构建优化目标
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 全量编译 | 15 分钟 | < 3 分钟 |
| 增量编译 | 5 分钟 | < 30 秒 |
| 依赖冲突 | 频繁发生 | 零发生(统一管控) |
| 环境切换 | 改代码/重打包 | 动态配置/一键切换 |
| 渠道打包 | 1 小时 | < 5 分钟 |
2 Gradle 现代化:Kotlin DSL + Version Catalog
还在用 Groovy 写build.gradle?是时候升级了。Groovy 是动态语言,IDE 提示弱,重构难。企业级项目必须使用Kotlin DSL。
2.1 迁移到 Kotlin DSL
步骤 1:重命名文件。
build.gradle→build.gradle.ktssettings.gradle→settings.gradle.kts
步骤 2:修改settings.gradle.kts。
// settings.gradle.ktspluginManagement{repositories{google()mavenCentral()gradlePluginPortal()}}dependencyResolutionManagement{repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories{google()mavenCentral()maven{url=uri("https://jitpack.io")}}}rootProject.name="EnterpriseApp"include(":app-shell")include(":component-login")include(":component-home")include(":module-base")步骤 3:修改build.gradle.kts(以module-base为例)。
// module-base/build.gradle.ktsplugins{id("com.android.library")id("org.jetbrains.kotlin.android")}android{namespace="com.example.module.base"compileSdk=34defaultConfig{minSdk=21targetSdk=34}buildTypes{release{isMinifyEnabled=falseproguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro")}}}dependencies{implementation("androidx.core:core-ktx:1.12.0")implementation("androidx.appcompat:appcompat:1.6.1")}2.2 Version Catalog(依赖统一管理的终极方案)
不要再在各个 Module 里写版本号了!Gradle 7.0+ 提供了Version Catalog,这是官方推荐的统一依赖管理方式。
步骤 1:创建gradle/libs.versions.toml。
[versions] kotlin = "1.9.20" agp = "8.2.0" compose = "1.5.4" material = "1.11.0" glide = "4.16.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "kotlin" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version = "1.6.1" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }步骤 2:在build.gradle.kts中使用。
// module-base/build.gradle.ktsplugins{alias(libs.plugins.android.library)alias(libs.plugins.kotlin.android)}dependencies{implementation(libs.androidx.core.ktx)implementation(libs.androidx.appcompat)implementation(libs.material)implementation(libs.glide)}收益:
- 版本唯一:所有 Module 强制使用同一个版本。
- 升级方便:只改
toml文件,不用动业务代码。 - IDE 支持:点击跳转,重构安全。
3 编译加速:从 15 分钟到 1 分钟
这是本篇最核心的干货。Gradle 提供了多种加速手段,你必须全部打开。
3.1 Configuration Cache(配置缓存)
痛点:Gradle 每次编译都要重新配置 Task 依赖图,非常耗时。
解法:Configuration Cache 把配置结果缓存起来。
开启方式:
在gradle.properties中添加:
org.gradle.configuration-cache=true org.gradle.configuration-cache.problems=warn效果:第二次编译时,跳过配置阶段,直接执行 Task。
3.2 Build Cache(构建缓存)
痛点:A 组件编译过的产物,B 组件依赖它时还要再编译一次。
解法:Build Cache 把编译产物(如 AAR)缓存起来。
开启方式:
org.gradle.caching=true3.3 Parallel Execution(并行编译)
痛点:Gradle 默认串行执行 Task。
解法:开启并行。
org.gradle.parallel=true3.4 守护进程(Daemon)
确保开启(默认开启):
org.gradle.configureondemand=true3.5 Kotlin 增量编译
确保 Kotlin 插件开启了增量编译(默认开启):
tasks.withType<KotlinCompile>().configureEach{kotlinOptions{incremental=true}}3.6 实战:优化前后的对比
假设有 20 个 Module。
| 优化手段 | 全量编译时间 |
|---|---|
| 无优化 | 15 min |
| + Configuration Cache | 10 min |
| + Build Cache | 7 min |
| + Parallel | 5 min |
| + Kotlin 增量 | 3 min |
最终效果:冷编译 3 分钟,热编译(改一行代码)30 秒。
4 依赖隔离与冲突解决
组件化后,依赖冲突是最大的坑。
4.1 依赖传递规则
规则:基础模块用implementation,业务组件用api谨慎。
implementation:依赖只在当前 Module 可见,不传递给上游。(推荐)api:依赖会传递给上游。(慎用,容易导致依赖爆炸)
错误示范:
// component-login/build.gradle.ktsdependencies{api(libs.glide)// 错误!所有依赖 login 的组件都会间接依赖 Glide}正确示范:
dependencies{implementation(libs.glide)// 只有 login 组件能用}4.2 统一第三方库版本
通过Version Catalog我们已经解决了。
4.3 排除冲突(Exclude)
有时第三方库会引入冲突的依赖。
dependencies{implementation(libs.some.sdk){exclude(group="com.google.android",module="support-v4")}}5 多环境配置:Dev / Test / Prod
组件化后,每个组件都有自己的BuildConfig。如何统一管理?
5.1 方案一:Gradle 多 Flavor(推荐)
步骤 1:在壳工程和所有组件中定义 Flavor。
// app-shell/build.gradle.ktsandroid{flavorDimensions+="env"productFlavors{create("dev"){dimension="env"buildConfigField("String","BASE_URL","\"http://dev.api.com\"")buildConfigField("boolean","LOG_DEBUG","true")}create("test"){dimension="env"buildConfigField("String","BASE_URL","\"http://test.api.com\"")buildConfigField("boolean","LOG_DEBUG","true")}create("prod"){dimension="env"buildConfigField("String","BASE_URL","\"https://api.com\"")buildConfigField("boolean","LOG_DEBUG","false")}}}步骤 2:组件中同步配置(使用publishNonDefault确保依赖正确)。
// component-login/build.gradle.ktsandroid{flavorDimensions+="env"productFlavors{create("dev"){dimension="env"}create("test"){dimension="env"}create("prod"){dimension="env"}}}步骤 3:代码中使用。
// 任何组件中if(BuildConfig.LOG_DEBUG){Log.d(TAG,"Debug Mode")}Retrofit.Builder().baseUrl(BuildConfig.BASE_URL).build()打包命令:
./gradlew assembleDevDebug ./gradlew assembleProdRelease5.2 方案二:使用buildConfigField动态切换
如果不想用 Flavor(因为 Flavor 会导致变体爆炸),可以用 BuildConfig 字段。
在gradle.properties中定义:
ENV_TYPE=dev在build.gradle.kts中读取:
valenvType=project.findProperty("ENV_TYPE")?:"dev"android{buildTypes{release{buildConfigField("String","ENV_TYPE","\"$envType\"")}}}6 多渠道打包:极速方案
传统的多渠道打包(在 Manifest 中写占位符)需要编译多次。我们要用美团 VasDolly或腾讯 ApkChannelPackage,实现一次编译,多次写入渠道。
6.1 集成 VasDolly
步骤 1:根目录build.gradle.kts。
buildscript{dependencies{classpath("com.meituan.android.walle:plugin:1.1.7")}}步骤 2:壳工程app-shell/build.gradle.kts。
plugins{id("com.android.application")id("walle")}walle{// 指定渠道包的输出路径apkOutputFolder=file("${project.buildDir}/outputs/channels")// 指定渠道配置文件channelFile=file("channel.txt")}步骤 3:创建channel.txt。
xiaomi huawei oppo vivo yingyongbao步骤 4:打包。
./gradlew clean assembleReleaseChannels效果:只编译一次 Release 包,瞬间生成 5 个渠道包。
6.2 代码中获取渠道
importcom.meituan.android.walle.WalleChannelReaderclassAppShell:Application(){overridefunonCreate(){super.onCreate()valchannel=WalleChannelReader.getChannel(this)Log.d("App","Channel:$channel")}}7 包体积优化(组件化必做)
组件多了,包体积容易变大。
7.1 开启资源缩减
buildTypes{release{isMinifyEnabled=trueisShrinkResources=true// 移除无用资源proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))}}7.2 图片压缩与 WebP
- 所有 PNG 转为 WebP。
- 使用 TinyPNG 压缩。
7.3 动态下发
非首屏必须的组件(如客服、反馈),考虑使用动态下发(Dynamic Feature Module)或插件化。
8 企业级 Gradle 配置模版(直接复制用)
这是经过大厂验证的gradle.properties配置:
# 基础配置 org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.caching=true # 关键:Configuration Cache org.gradle.configuration-cache=true org.gradle.configuration-cache.problems=warn # Android android.useAndroidX=true android.enableJetifier=true android.nonTransitiveRClass=true # Kotlin kotlin.incremental=true kotlin.caching.enabled=true9 总结:构建系统的“军规”
- 统一工具链:Kotlin DSL + Version Catalog。
- 必须开缓存:Configuration Cache + Build Cache。
- 依赖要收敛:基础模块
implementation,禁止滥用api。 - 环境要隔离:Flavor 管理 Dev/Test/Prod。
- 渠道要极速:VasDolly 一次编译多渠道。
至此,我们的组件化架构已经具备了:
- 物理隔离(代码不耦合)
- 通信解耦(路由)
- 构建极速(Gradle 优化)
- 环境可控(多 Flavor)
- 发布高效(多渠道)
下一篇预告:
系列三:组件化与模块化进阶 | 第10篇:组件通信与路由(ARouter 核心落地)
我们将深入 ARouter 的源码,讲解跨组件服务调用(Service Provider)、降级策略、以及路由表的动态更新。
如果你的项目编译还在 10 分钟以上,请立即执行本文的优化方案。这不仅是技术优化,更是对团队生命的尊重。
