Skip to content

多模块项目架构

源:Android 官方文档 - Projects overview

多模块项目通过将应用拆分为多个独立模块,实现代码复用、加快构建速度和强制模块边界。

模块类型

Application 模块

应用的入口点,包含应用级代码和资源。

kotlin
// app/build.gradle.kts
plugins {
    id("com.android.application")
}

android {
    namespace = "com.example.myapp"
    
    defaultConfig {
        applicationId = "com.example.myapp"
    }
}

dependencies {
    implementation(project(":core"))
    implementation(project(":feature-login"))
}

特点

  • 每个项目只能有一个 application 模块
  • 生成 APK/AAB
  • 定义 applicationId

Library 模块

可复用的代码库,可被多个模块依赖。

kotlin
// core/build.gradle.kts
plugins {
    id("com.android.library")
}

android {
    namespace = "com.example.core"
}

dependencies {
    api("androidx.core:core-ktx:1.15.0")
}

特点

  • 生成 AAR 文件
  • 可被其他模块依赖
  • 不能独立运行

Dynamic Feature 模块

按需下载的功能模块,减小初始安装体积。

kotlin
// feature-camera/build.gradle.kts
plugins {
    id("com.android.dynamic-feature")
}

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

dependencies {
    implementation(project(":app"))
}

在 app 模块中声明:

kotlin
// app/build.gradle.kts
android {
    dynamicFeatures += setOf(":feature-camera", ":feature-gallery")
}

Test Fixtures 模块 AGP 7.1+

提供测试辅助代码,可在多个模块间共享测试工具。

kotlin
// core/build.gradle.kts
plugins {
    id("com.android.library")
    id("java-test-fixtures")
}

dependencies {
    // 测试辅助代码的依赖
    testFixturesImplementation("junit:junit:4.13.2")
}

使用:

kotlin
// feature-login/build.gradle.kts
dependencies {
    testImplementation(testFixtures(project(":core")))
}

模块间依赖

implementation

依赖不传递,推荐用于大多数场景。

kotlin
dependencies {
    implementation(project(":core"))
}

api

依赖传递,仅在需要暴露传递依赖时使用。

kotlin
// core/build.gradle.kts
dependencies {
    api("com.squareup.retrofit2:retrofit:2.9.0")  // 暴露给依赖core的模块
}

// app/build.gradle.kts
dependencies {
    implementation(project(":core"))  // 自动获得 Retrofit 依赖
}

路径依赖

kotlin
dependencies {
    implementation(project(":libraries:networking"))
    implementation(project(":features:login"))
}

项目结构示例

按功能分层

MyApp/
├── app/                    # Application模块
├── core/                   # 核心库
│   ├── common/            # 通用工具
│   ├── network/           # 网络层
│   └── database/          # 数据库
├── features/              # 功能模块
│   ├── login/
│   ├── home/
│   └── profile/
└── libraries/             # 第三方库封装
    └── analytics/

配置:

kotlin
// settings.gradle.kts
include(":app")
include(":core:common")
include(":core:network")
include(":core:database")
include(":features:login")
include(":features:home")
include(":features:profile")
include(":libraries:analytics")

按层次分层

MyApp/
├── app/                    # UI层
├── domain/                 # 业务逻辑层
├── data/                   # 数据层
└── presentation/           # 展示层

约定插件(Convention Plugins)

创建可复用的构建逻辑,避免重复配置。

创建约定插件

创建 buildSrc 模块

MyApp/
└── buildSrc/
    ├── build.gradle.kts
    └── src/main/kotlin/
        ├── AndroidLibraryConventionPlugin.kt
        └── AndroidFeatureConventionPlugin.kt

buildSrc/build.gradle.kts

kotlin
plugins {
    `kotlin-dsl`
}

dependencies {
    implementation("com.android.tools.build:gradle:8.7.3")
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0")
}

AndroidLibraryConventionPlugin.kt

kotlin
import com.android.build.gradle.LibraryExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class AndroidLibraryConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("com.android.library")
                apply("org.jetbrains.kotlin.android")
            }
            
            extensions.configure<LibraryExtension> {
                compileSdk = 34
                
                defaultConfig {
                    minSdk = 24
                }
                
                compileOptions {
                    sourceCompatibility = JavaVersion.VERSION_17
                    targetCompatibility = JavaVersion.VERSION_17
                }
            }
        }
    }
}

使用约定插件

kotlin
// core/build.gradle.kts
plugins {
    id("android-library-convention")  // 使用约定插件
}

android {
    namespace = "com.example.core"
}

Composite Build

将多个独立项目组合在一起,适合大型项目或多团队协作。

配置 Composite Build

kotlin
// settings.gradle.kts
includeBuild("../shared-library")
includeBuild("../common-utils")

include(":app")
include(":feature-login")

使用 includedBuild 依赖

kotlin
// app/build.gradle.kts
dependencies {
    implementation("com.example:shared-library:1.0.0")  // 来自 includedBuild
}

依赖管理最佳实践

Version Catalog 集中管理

toml
# gradle/libs.versions.toml
[versions]
kotlin = "2.1.0"
retrofit = "2.9.0"

[libraries]
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }

[bundles]
retrofit = ["retrofit", "retrofit-converter-gson"]

使用:

kotlin
dependencies {
    implementation(libs.bundles.retrofit)
}

避免循环依赖

错误示例

app -> core -> utils -> core  # 循环依赖

正确方式

app -> core -> utils
    -> common

模块化策略

按功能模块化

优点

  • 清晰的功能边界
  • 便于团队分工
  • 支持动态交付

示例

:features:login
:features:home
:features:settings

按层次模块化

优点

  • 强制分层架构
  • 避免跨层调用
  • 便于单元测试

示例

:presentation
:domain
:data

混合模块化

结合功能和层次,适合大型项目。

:app
:features:login:ui
:features:login:domain
:features:login:data
:core:network
:core:database

构建优化

使用 Gradle 并行编译

properties
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true

减少模块依赖

  • 避免不必要的 api 依赖
  • 使用 implementation 代替 api
  • 定期检查依赖树
bash
./gradlew :app:dependencies

增量编译

合理划分模块,修改单个模块时仅重新编译相关模块。

测试多模块项目

共享测试代码

使用 Test Fixtures:

kotlin
// core/build.gradle.kts
plugins {
    id("java-test-fixtures")
}

// feature-login/build.gradle.kts
dependencies {
    testImplementation(testFixtures(project(":core")))
}

模块间集成测试

kotlin
// app/build.gradle.kts
dependencies {
    androidTestImplementation(project(":core"))
    androidTestImplementation(project(":feature-login"))
}

最佳实践

明确模块边界

  • 定义清晰的模块职责
  • 避免模块间紧耦合
  • 使用接口定义模块契约

合理拆分粒度

  • 避免过度拆分(管理成本高)
  • 避免拆分不足(编译慢)
  • 根据团队规模调整

依赖方向一致

  • 低层模块不依赖高层模块
  • 业务模块不依赖UI模块
  • 定义清晰的依赖层级

使用约定插件

  • 提取common配置
  • 统一编译选项
  • 简化模块配置

监控构建时间

  • 使用 Build Analyzer
  • 定期检查模块依赖
  • 优化慢速模块