4. 创建模块并定义模块类型

Gradle 多模块项目中的每个子模块都是一个独立的构建单元,其类型由所应用的插件决定。正确声明模块并选择对应插件是实现模块化拆分的起点。本章将系统讲解如何在 settings.gradle 中注册模块、如何为模块应用 Java Library、Application、Kotlin 和 Android 插件,以及各插件之间的关键差异。

1. 模块声明与目录结构

在 Gradle 多模块项目中,所有子模块必须在根项目的 settings.gradle(或 settings.gradle.kts)中显式声明。每个模块对应一个独立的子目录,该目录下必须包含 build.gradle 文件。

命名规范: 模块名称通常采用小写连字符形式(如 core-utils),目录名与模块名保持一致。避免使用驼峰或空格。
// settings.gradle(Groovy DSL)
rootProject.name = 'my-multi-module'
include 'core-library'
include 'app'
include 'toolkit'
include 'android-app'
// 对应的目录结构
my-multi-module/
├── settings.gradle
├── build.gradle          // 根项目构建脚本
├── core-library/
│   └── build.gradle
├── app/
│   └── build.gradle
├── toolkit/
│   └── build.gradle
└── android-app/
    └── build.gradle

2. 插件类型与应用方式

每个子模块的 build.gradle 通过 plugins { id '...' } 块声明构建类型。下表列出最常用的四大插件类型及其适用场景。

插件 ID 模块类型 适用场景 生成产物
java-library Java 库 封装可复用的 Java 工具类、业务逻辑、数据模型 JAR
application Java 应用程序 包含 main 方法的可运行 Java 程序 可执行 JAR / 启动脚本
org.jetbrains.kotlin.jvm Kotlin 库 纯 Kotlin 编写的公共模块,可被 Java/Kotlin 调用 JAR(含 Kotlin 标准库)
com.android.application Android 应用 构建 Android APK 的入口模块 APK / AAB
插件与语言配置的关系: 应用 java-library 或 application 后,Gradle 会自动启用 Java 编译任务;若需混合 Kotlin 代码,应额外添加 org.jetbrains.kotlin.jvm 插件,或直接使用 org.jetbrains.kotlin.jvm 代替 Java 插件。

3. 各模块构建脚本示例

3.1 Java 库模块(core-library)

// core-library/build.gradle
plugins {
    id 'java-library'
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

dependencies {
    // 对外暴露的 API 依赖
    api 'com.google.guava:guava:32.0.1-jre'
    // 内部实现依赖
    implementation 'org.slf4j:slf4j-api:2.0.0'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}

3.2 应用模块(app)

// app/build.gradle
plugins {
    id 'application'
}

application {
    mainClass = 'com.example.Main'
}

dependencies {
    implementation project(':core-library')
    implementation 'org.slf4j:slf4j-simple:2.0.0'
}

3.3 Kotlin 库模块(toolkit)

// toolkit/build.gradle
plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.9.0'
}

kotlin {
    jvmToolchain(17)
}

dependencies {
    implementation 'org.jetbrains.kotlin:kotlin-stdlib'
    implementation project(':core-library')
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
}

3.4 Android 应用模块(android-app)

// android-app/build.gradle
plugins {
    id 'com.android.application' version '8.1.0'
    id 'org.jetbrains.kotlin.android' version '1.9.0'
}

android {
    namespace 'com.example.androidapp'
    compileSdk 34
    defaultConfig {
        applicationId 'com.example.androidapp'
        minSdk 21
        targetSdk 34
        versionCode 1
        versionName '1.0'
    }
}

dependencies {
    implementation project(':core-library')
    implementation project(':toolkit')
    implementation 'androidx.appcompat:appcompat:1.6.1'
}

4. 模块类型选择与插件应用流程

下面的 SVG 图展示了典型多模块项目中各模块的插件选择关系。根项目不应用业务插件,仅负责协调子模块;子模块根据职责(库、应用、Android 等)选择特定插件。

多模块项目:模块类型与插件应用 根项目(settings.gradle) core-library java-library 插件 app application 插件 toolkit kotlin.jvm 插件 android-app com.android.application + kotlin.android 依赖关系: App → core-library Android → core-library, toolkit

5. 常见错误与避坑指南

避免插件重复应用: 如果一个模块同时应用 java-library 和 application,将导致任务冲突(jar vs distZip)。库模块和可运行模块应严格分离。
  • Kotlin 插件版本与 Gradle 版本不匹配: 使用 org.jetbrains.kotlin.jvm 时,插件版本必须与编译环境兼容。建议查看 Kotlin Gradle 插件兼容矩阵。
  • Android 模块必须放在单独的项目或子模块中: 不要在同一个模块中同时使用 com.android.application 和 java-library;若共享代码,应抽取为 android-library 模块。
  • 模块名称与目录名不一致: 如果 include 'my-module' 但目录名是 my_module,Gradle 会报模块未找到错误。目录名需与 include 中的名称完全一致(大小写敏感)。

6. 调试与验证

创建模块后,可以使用以下命令验证模块是否被正确识别:

# 列出所有项目(含根项目和子模块)
gradle projects

# 查看特定模块的构建任务
gradle :app:tasks

# 编译单个模块
gradle :core-library:build
实践建议: 在大型多模块项目中,建议为每个模块单独执行 gradle :模块名:check 确保编译通过,再逐步联调。利用 gradle build --dry-run 可预览任务执行顺序,避免依赖循环。