--- title: "Android多模块架构与Gradle构建优化" date: "2026-04-24" readTime: "33分钟" tags: ["Android", "Gradle", "多模块", "构建优化", "架构设计"] ---

Android多模块架构与Gradle构建优化 - i开源架构

引言

随着 Android 应用规模从几万行增长到几十万行,单模块工程的维护成本呈指数级上升:编译时间暴涨、代码边界模糊、团队协作冲突频发。多模块架构是解决这些问题的必经之路,但错误的模块划分或构建配置同样会让工程陷入"模块地狱"。本文从模块类型设计、API 边界管理、Gradle 增量构建机制、版本对齐策略到诊断工具,系统性地阐述大型 Android 项目的工程化实践。

一、模块类型体系设计

1.1 四大核心模块类型

在成熟的大型 Android 项目中,模块并非随意划分,而是根据职责边界和技术特性形成清晰的类型层级:

模块类型层次
app/                          ← 应用程序壳(Application Shell)
├── feature/                   ← 功能模块(按业务能力垂直拆分)
│   ├── feature-home/
│   ├── feature-profile/
│   ├── feature-search/
│   └── feature-payment/
├── lib/                       ← 共享基础库(横向复用)
│   ├── lib-ui/               ← 公共 UI 组件
│   ├── lib-network/          ← 网络层封装
│   ├── lib-database/         ← 数据库层封装
│   ├── lib-analytics/        ← 埋点/分析
│   └── lib-common/           ← 工具类/扩展函数
└── dynamic-feature/          ← 按需下载的功能模块
    ├── df-wallet/
    └── df-live-streaming/

各模块类型的职责定义:

  • app:应用入口点,持有 Application 类、Activity 栈,不包含任何业务逻辑,负责组装各个 Feature 模块。
  • feature:业务功能的完整封装,包括 UI(Compose/View)、ViewModel、Repository、UseCase,一个 Feature 对应一个完整的用户故事。
  • lib:纯技术层封装,无 Android 上下文依赖(或仅依赖轻量上下文),可被任意模块复用。
  • dynamic-feature:通过 Play Feature Delivery 实现按需下载,适合用户可选功能(如高级会员功能)。

1.2 Feature 模块的内部结构

一个标准 Feature 模块应遵循 Clean Architecture 的内层依赖原则:

feature 模块标准结构
// feature-search 模块目录结构
feature-search/
├── build.gradle.kts
├── src/
│   ├── main/
│   │   ├── kotlin/com/example/feature/search/
│   │   │   ├── di/               ← Hilt 模块,仅声明本模块内的依赖绑定
│   │   │   │   └── SearchModule.kt
│   │   │   ├── data/             ← 数据层
│   │   │   │   ├── remote/       ← DTO、ApiService
│   │   │   │   ├── local/        ← DAO、Entity
│   │   │   │   └── repository/   ← SearchRepositoryImpl
│   │   │   ├── domain/           ← 领域层
│   │   │   │   ├── model/        ← Domain Model(业务概念,不依赖框架)
│   │   │   │   ├── repository/   ← Repository 接口(抽象契约)
│   │   │   │   └── usecase/     ← 业务用例
│   │   │   └── presentation/    ← 表现层
│   │   │       ├── ui/           ← Composable / View
│   │   │       ├── viewmodel/    ← ViewModel
│   │   │       └── SearchContract.kt  ← UiState + Intent + Effect
│   │   └── res/
│   │       ├── values/strings.xml
│   │       └── layout/           ← 混合方案:XML 布局片段
│   └── androidTest/             ← Feature 独立测试
│       └── SearchRepositoryTest.kt

关键原则:Feature 模块之间的通信必须通过稳定的公开 API 进行——即 Domain 层的 UseCase 接口。永远不要让一个 Feature 直接依赖另一个 Feature 的 Repository 实现,否则会形成循环依赖或紧耦合陷阱。

1.3 Dynamic Feature 的使用场景

Dynamic Feature(DFD,Dynamic Feature Delivery)通过 Google Play 的 App Bundle 机制实现模块的按需下载。但它并非银弹——DF 模块有约 10MB 的压缩体积上限和额外的首次下载延迟,需要谨慎评估:

Dynamic Feature 配置
// app/build.gradle.kts
android {
    bundle {
        language {
            // 按语言拆分为独立的语言包
            enableSplit = true
        }
        density {
            enableSplit = true  // 按屏幕密度拆分
        }
        abi {
            enableSplit = true  // 按 CPU 架构拆分(arm64-v8a / armeabi-v7a)
        }
    }
}

// wallet/build.gradle.kts(Dynamic Feature)
android {
    // 模块类型声明
    bundle {
        // 是否在安装时就包含(false = 按需下载)
        deliveryTask = ModuleDeliveryTask(ondemand = true)
    }
}

// 使用 SplitInstallManager 触发按需加载
class PaymentFragment : Fragment() {
    private val splitInstallManager by lazy {
        SplitInstallManagerFactory.create(requireContext())
    }
    
    private fun installWalletFeature() {
        val request = SplitInstallRequest.newBuilder()
            .addModule("wallet")
            .build()
        
        splitInstallManager.startSplitInstall(request)
            .addOnSuccessListener { sessionId ->
                // 下载完成,动态注册路由
                Router.registerFeature("wallet", WalletEntryPoint())
            }
            .addOnFailureListener { error ->
                Timber.e(error, "Wallet feature download failed")
            }
    }
}

二、API 边界设计:implementation vs api

2.1 Gradle 依赖变体的本质

理解 implementationapi 的区别,本质上是理解 Gradle 的依赖传递图构建策略:

implementation vs api 传递性对比
// lib-network/build.gradle.kts
dependencies {
    // 场景 A:使用 api(等同于旧版 compile)
    // app → feature-search → lib-network → okHttp
    // app 和 feature-search 都能访问 okHttp 的类
    api("com.squareup.okhttp3:okhttp:4.12.0")
    
    // 场景 B:使用 implementation(推荐默认)
    // app → feature-search → lib-network → retrofit
    // app 无法访问 retrofit(依赖被"隐藏"了)
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
}

// 实际编译图对比:
//
// api 模式(传递暴露):
//   app
//    ├── feature-search
//    │    └── lib-network
//    │         ├── okHttp ← app 可访问
//    │         └── retrofit ← app 不可访问
//    └── lib-network (okHttp 暴露到传递链)
//
// implementation 模式(传递隔离):
//   app
//    └── feature-search
//         └── lib-network
//              ├── okHttp ← app 不可访问
//              └── retrofit ← app 不可访问

建议原则:lib 模块默认使用 implementation,只在 API 明确需要被下游使用时切换为 api。每次使用 api 前问自己:"这个依赖是否应该成为公共契约的一部分?"

2.2 依赖变体的分层策略

大型项目推荐采用三段式依赖策略,最大化复用率的同时控制编译时间:

三段式依赖策略
// ==============================
// 层级一:Core(最小内核,无任何业务概念)
// ==============================
// lib-common/build.gradle.kts
dependencies {
    // 纯 Kotlin 标准库扩展,无 Android 依赖
    implementation("org.jetbrains.kotlin:kotlin-stdlib")
    implementation("net.ltgt.gradle.incap:incap:0.3")  // 注解处理器增强
    
    // 仅允许 api 暴露极稳定的类型
    api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
    // 注意:Coroutines Android 依赖应放在 lib-android-common 中
}

// ==============================
// 层级二:Android 基础库(UI / 框架封装)
// ==============================
// lib-android-common/build.gradle.kts
plugins {
    id("com.android.library")
    kotlin("android")
    kotlin("kapt")
}

android {
    namespace = "com.example.lib.android.common"
}

dependencies {
    // 隐藏实现细节
    implementation(project(":lib-common"))
    
    // Android 框架依赖,隐藏到 lib 内
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
    implementation("androidx.compose.ui:ui:1.6.0")
    implementation("androidx.compose.material3:material3:1.2.0")
    
    // 如果这些是业务层必须使用的类型,才暴露为 api
    api("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}

// ==============================
// 层级三:Feature 模块(业务封装)
// ==============================
// feature-search/build.gradle.kts
dependencies {
    // 只依赖稳定的抽象层,不依赖实现细节
    implementation(project(":lib-android-common"))
    implementation(project(":lib-network"))  // 仅需网络接口
    
    // 依赖注入
    implementation("com.google.dagger:hilt-android:2.50")
    kapt("com.google.dagger:hilt-compiler:2.50")
}

2.3 版本对齐问题:Diamond 依赖

当多个模块依赖同一个库的不同的版本时,Gradle 默认采用"最新版本覆盖"策略(最新契合法)。这在语义上可能导致运行时崩溃:

Diamond 依赖冲突场景
// Diamond 依赖冲突示意:
//
//     app
//      │
//      ├── feature-A ──→ lib-X:2.1.0(依赖 OkHttp 4.11)
//      │
//      └── feature-B ──→ lib-X:1.9.0(依赖 OkHttp 4.9)
//
// Gradle 决议:选择 2.1.0
// 风险:lib-X:1.9.0 的代码可能调用了已被移除的 OkHttp API
// 结果:NoSuchMethodError 或 ClassNotFoundException 在运行时爆发

解决方案是使用 Gradle BOM(Bill of Materials)统一版本仲裁,这在下一节详细展开。

三、增量构建与 Gradle 构建优化

3.1 配置缓存(Configuration Cache)

Gradle 配置阶段(Configuration Phase)是构建性能的最大瓶颈之一——每次构建都会重新计算所有模块的依赖图。配置缓存将配置阶段的输出序列化到磁盘,后续构建直接复用:

配置缓存配置
// gradle.properties
org.gradle.configuration-cache=true
org.gradle.configuration-cache.problems=warn  # 首次启用用 warn,逐步改为 fail

// 在 CI 环境预热配置缓存
// .github/workflows/build.yml
- name: Warm Gradle Configuration Cache
  uses: actions/cache@v4
  with:
    path: |
      ~/.gradle/caches/transforms-*
      ~/.gradle/configuration-cache
    key: gradle-conf-${{ runner.os }}-${{ hashFiles('**/*.gradle.kts', '**/gradle-wrapper.properties') }}
    restore-keys: |
      gradle-conf-${{ runner.os }}-

- name: Build with Configuration Cache
  run: ./gradlew assembleDebug --configuration-cache

注意:配置缓存对构建脚本有严格要求——所有 build.gradle.kts 中的任务创建必须是幂等的,且不能直接访问 File 系统的时间戳(因为缓存结果会被不同机器复用)。使用 Kotlin DSL 的 providers API(Gradle 8.x+)是配置缓存友好的写法。

3.2 并行任务与任务裁剪

在多模块项目中,合理的并行化可以成倍缩短编译时间:

并行构建与任务裁剪
// gradle.properties
org.gradle.parallel=true          // 启用模块间并行
org.gradle.caching=true           // 启用任务输出缓存
org.gradle.workers.max=4          // 限制 worker 数量(避免内存溢出)
org.gradle.jvmargs=-Xmx4096m      // 充足内存是并行的前提

// 在根 build.gradle.kts 中配置任务图优化
tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}

// 增量编译的关键:避免全量编译所有 feature
// 通过任务依赖图分析,让 assembleDebug 只编译必要的模块
tasks.register("assembleCurrentFeature", Task::class) {
    val currentFeature = project.findProperty("currentFeature") as String?
    dependsOn(":feature-$currentFeature:assembleDebug")
}

// 增量 lint(只 lint 改动的模块)
tasks.register("lintChanged", Lint::class) {
    val changedFiles = providers.exec {
        workingDir = rootDir
        commandLine("git", "diff", "--name-only", "HEAD", "--diff-filter=M")
    }.standardOutput.asText.get().split("\n").filter { it.endsWith(".kt") }
    
    changedFiles.forEach { file ->
        val containingModule = findModuleForFile(file)
        dependsOn(":$containingModule:lint")
    }
}

3.3 Kotlin DSL 与 Gradle 脚本的模块化

Kotlin DSL 相比 Groovy DSL 提供了编译期类型检查、IDE 智能提示和重构安全。在大型项目中,应将公共配置抽取为 convention plugins:

Convention Plugin 架构
// buildSrc/src/main/kotlin/
// Convention Plugin: AndroidLibraryConvention.kt
plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
    id("org.jetbrains.kotlin.kapt")
}

android {
    compileSdk = 34
    
    defaultConfig {
        minSdk = 24
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
        isCoreLibraryDesugaringEnabled = true
    }
    
    kotlinOptions {
        freeCompilerArgs += listOf(
            "-opt-in=kotlin.RequiresOptIn",
            "-Xcontext-receivers"  // 实验性功能
        )
    }
    
    // 统一配置 lint
    lint {
        warningsAsErrors = true
        checkDependencies = true
        // 按模块忽略特定的 lint 错误(如迁移期间的兼容性问题)
        disable += listOf("ObsoleteSdkInt", "InvokeSingularMethod")
    }
}

dependencies {
    // 所有 Library 模块的共同依赖
    "coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.0.4")
    implementation("androidx.core:core-ktx:1.12.0")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
}

// Feature Convention Plugin: FeatureLibraryConvention.kt
// 继承基础 Library Convention,添加 Feature 特有配置
plugins.apply()

android {
    namespace = "com.example.feature.$featureName"
    
    // Feature 模块额外开启的编译器优化
    kotlin {
        compilerOptions {
            freeCompilerArgs.add("-P")
            freeCompilerArgs.add("plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true")
        }
    }
}
使用 Convention Plugin
// feature-search/build.gradle.kts
plugins {
    id("com.example.android.feature")  // 应用自定义 Convention Plugin
}

android {
    namespace = "com.example.feature.search"
}

dependencies {
    // Feature 模块特殊依赖
    implementation(project(":lib-network"))
    implementation(project(":lib-ui"))
    implementation(project(":lib-common"))
}

四、版本对齐:Gradle BOM 与依赖仲裁

4.1 BOM 的使用与自定义 BOM

Gradle BOM 本身是一个特殊的 POM 文件,它不包含代码,仅声明各依赖的推荐版本。使用 BOM 可以避免 Diamond 依赖冲突,同时减少 version 声明的维护负担:

BOM 统一版本管理
// gradle/dependencies.toml(Gradle 8.x 新格式,推荐)
[versions]
agp = "8.2.2"
kotlin = "1.9.22"
compose-compiler = "1.5.8"
compose-bom = "2024.02.00"
lifecycle = "2.7.0"
hilt = "2.50"
coroutines = "1.8.0"
retrofit = "2.9.0"
okhttp = "4.12.0"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCoreKtx" }
compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "composeBom" }
compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "composeBom" }
// ...

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }

// 使用 BOM(所有未指定版本的 androidx.* 依赖使用 BOM 推荐的版本)
dependencies {
    // BOM 方式:覆盖所有 androidx.* 的版本
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    androidImplementation(platform("androidx.compose:compose-bom:2024.02.00"))
    
    // 这些库的版本由 BOM 统一控制,无需重复声明版本
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx")
    
    // 非 BOM 库,单独指定版本
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("com.google.dagger:hilt-android:2.50")
    kapt("com.google.dagger:hilt-compiler:2.50")
}

// 自定义企业级 BOM(用于统一多团队依赖版本)
// version-catalog/bom-catalog.toml
[versions]
# 关键库统一版本管理
network = "2.9.0"       # Retrofit 2.9.0
okhttp = "4.12.0"
moshi = "1.15.1"

[libraries]
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "network" }
retrofit-converter = { group = "com.squareup.retrofit2", name = "converter-moshi", version.ref = "network" }
okhttp-core = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }

4.2 依赖仲裁与强制版本

当某个间接依赖引入了一个已知不兼容的版本时,使用 constraints 强制覆盖:

依赖约束与强制覆盖
dependencies {
    // 强制所有 okhttp 间接依赖使用统一版本
    constraints {
        implementation("com.squareup.okhttp3:okhttp:4.12.0") {
            because("4.11 以下版本存在 TLS 握手漏洞 CVE-2023-xxx")
        }
        implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") {
            because("必须与 okhttp 主库版本对齐")
        }
    }
    
    // resolutionStrategy:全局覆盖任意模块的依赖版本
    configurations.all {
        resolutionStrategy {
            // 强制所有配置使用固定的 okhttp 版本
            force("com.squareup.okhttp3:okhttp:4.12.0")
            force("com.squareup.okhttp3:logging-interceptor:4.12.0")
        }
    }
}

五、诊断工具

5.1 Build Scan 与构建分析

Gradle Build Scan(--scan)是诊断构建性能问题的终极工具,它将构建过程可视化并上传到 scans.gradle.com 或自建服务器:

Build Scan 使用方法
# 生成构建扫描报告
./gradlew assembleDebug --scan

# 输出:
# BUILD SUCCESSFUL
# Build scan link: https://gradle.com/s/abc123xyz

# 在 CI 中强制启用并上传到自有服务器
./gradlew assembleRelease \
  --scan \
  --no-build-cache \
  --rerun-tasks \
  -Dscan.upload.url=https://gradle.internal.company.com

# 本地查看配置缓存状态
./gradlew --status
# 输出:
# Configuration cache operations: 12 executed, 0 reused
# Task graph size: 47 modules, 312 tasks

Build Scan 报告中重点关注以下指标:

  • Configuration Time:配置阶段耗时,目标 < 30s
  • Task Execution Time:任务执行时间分布,找出耗时最长的任务
  • Task Dependencies:任务依赖图,识别不必要的串行链
  • Cache Hit Rate:缓存命中率,分析哪些任务未命中缓存

5.2 dependencyInsight 与依赖树分析

依赖诊断命令
# 查看特定依赖的版本来源
./gradlew :app:dependencies --configuration releaseRuntimeClasspath \
  --dependency insight okhttp

# 输出示例:
# com.squareup.okhttp3:okhttp:4.12.0 (forced)
# +--- project :lib-network
# |    +--- project :feature-payment
# |    |    +--- project :feature-search
# \--- project :feature-auth
#      \--- com.squareup.okhttp3:okhttp:4.11.0 -> 4.12.0 (forced)
#      强制版本覆盖生效:4.11.0 → 4.12.0

# 查看某模块的完整依赖树(排除测试/AndroidTest)
./gradlew :lib-network:dependencies \
  --configuration debugRuntimeClasspath \
  --console=plain \
  | grep -E "^\+---|^\+---" | head -50

# 分析未使用的传递依赖(清理优化)
./gradlew :app:buildHealth \
  --type=unused-dependencies

一个常见的性能陷阱:某个看起来"无害"的传递依赖(如 okio)可能拖慢了 R8/D8 的 DEX 编译速度。使用 dependencyInsight 追踪每个引入 okio 的路径,评估是否可以裁剪:

构建健康度检查
// build.gradle.kts
// 添加 build health 插件
plugins {
    id("com.autonomousapps.analysis") version "2.1.0"
}

// 运行健康度检查
tasks.register("buildHealth", com.autonomousapps.DependencyHealthTask::class) {
    analysis = setOf(
        Analysis.HELPERS,        // 检测未使用的 helper 类
        Analysis.ANDROID_WARNINGS,
        Analysis.UNUSED_DEPENDENCIES,
        Analysis.INCORRECT_DEPENDENCIES,
        Analysis.MISUSED_DEPENDENCIES
    )
    // 生成修复建议
    issues = Issues.WARNINGS
}

// 推荐将 build health 检查集成到 CI
// .github/workflows/ci.yml
- name: Dependency Health Check
  run: ./gradlew buildHealth
  # 失败时生成报告上传到 Artifacts

5.3 构建耗时分析实战

使用 Gradle Profiler 进行受控的性能基准测试:

Gradle Profiler 配置
# build-profile.conf
# Gradle Profiler: ./gradlew --profile 之外的更强大工具
# 安装:brew install gradle-profiler

main {
    versions = ["8.5"]
    gradle = "8.5"
    scenarios {
        "clean-assemble" {
            tasks = ["clean", "assembleDebug"]
            warm-ups = 3
            iterations = 5
            invocations = 1
            cleanup-tasks = ["clean"]
        }
        "incremental-change" {
            tasks = ["assembleDebug"]
            warm-ups = 2
            iterations = 3
            apply-patch = "patches/user-change.patch"
        }
    }
    measured-builds = 3
    measured-clean-builds = 3
    output = "build-profile-reports"
}

# 运行对比分析
# gradle-profiler --benchmark build-profile.conf

在优化前后运行 Gradle Profiler 对比,可以量化每项优化(如启用配置缓存、切换到 Kotlin DSL、升级 AGP 版本)的实际收益。

六、工程化最佳实践

6.1 模块化成熟度模型

模块化不是一步到位的工程决策。以下是一个可量化的成熟度评估框架:

模块化成熟度等级
等级 1 - 单一模块:全部代码在 app 模块中
  → 指标:1 个 build.gradle,编译时间 > 5min

等级 2 - 两层分离:app + lib(共享工具类)
  → 指标:2-3 个模块,lib 不依赖 Android Framework

等级 3 - Feature 拆分:app + lib + features
  → 指标:5-10 个模块,Feature 之间无直接依赖

等级 4 - Clean Architecture:feature 按 data/domain/presentation 分层
  → 指标:10-20 个模块,编译时间 < 3min

等级 5 - Dynamic Feature + 按需加载
  → 指标:> 20 个模块,Play Store App Bundle 开启

等级 6 - 独立模块独立发布(Module as a Library)
  → 指标:每个模块有独立 CI、版本号,可被多个 App 复用

6.2 CI/CD 流水线优化

多级 CI 构建策略
# .github/workflows/android-ci.yml(GitHub Actions 示例)
name: Android CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  # 级别 1:快速检查(< 3 分钟)
  quick-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: { java-version: '17', distribution: 'temurin' }
      - name: Gradle Cache
        uses: actions/cache@v4
        with:
          path: ~/.gradle/caches
          key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts', 'gradle-wrapper.properties') }}
      
      # 只 lint 改动的模块
      - name: Lint Changed Modules
        run: ./gradlew lintChanged --no-daemon
      
      - name: Unit Tests (Changed Modules)
        run: ./gradlew testChangedUnitTests --no-daemon

  # 级别 2:完整 Debug 构建(< 10 分钟,含配置缓存)
  full-debug:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: { java-version: '17', distribution: 'temurin' }
      - name: Build Debug APK
        run: ./gradlew assembleDebug --configuration-cache --no-daemon
      - name: Upload APK
        uses: actions/upload-artifact@v4
        with: { name: apk, path: app/build/outputs/apk/debug/*.apk }

  # 级别 3:Release 构建 + Benchmarks(仅 main 分支)
  release-build:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: { java-version: '17', distribution: 'temurin' }
      - name: Build Release AAB
        run: ./gradlew bundleRelease --configuration-cache --no-daemon
      - name: Macrobenchmark
        run: ./gradlew :benchmark:macroBenchmark --no-daemon
      - name: Upload Baseline Profile
        run: ./gradlew uploadBaselineProfile --no-daemon

总结

Android 多模块架构的精髓不在于"拆得多",而在于"拆得对"——按业务边界划分 Feature 模块,通过 Stable API 契约解耦,使用 implementation 隐藏实现细节,配合 Gradle BOM 统一版本仲裁,构建速度可以从数十分钟优化到三分钟以内。配置缓存、并行任务、Build Scan 诊断和 Gradle Profiler 基准测试,构成了完整的构建优化工具链。下一篇文章我们将深入 Kotlin Flow 响应式编程与背压机制,探索协程在生产环境中的最佳实践。