Gradle 构建基础
问题
Gradle 的核心概念有哪些?Android 项目的 Gradle 构建流程是怎样的?
答案
Gradle 核心概念
| 概念 | 说明 |
|---|---|
| Project | 每个 build.gradle 对应一个 Project,根项目负责全局配置 |
| Task | 构建的最小执行单元,如 compileKotlin、assembleDebug |
| Plugin | 扩展 Gradle 功能,如 com.android.application、kotlin-android |
| Configuration | 依赖作用域:implementation、api、compileOnly 等 |
| Build Script | build.gradle(.kts) 配置文件 |
构建生命周期三阶段
依赖配置对比
| 配置 | 编译时可见 | 运行时可见 | 传递依赖 | 使用场景 |
|---|---|---|---|---|
implementation | ✅ | ✅ | ❌ | 默认选择,内部使用 |
api | ✅ | ✅ | ✅ | 暴露给上层模块 |
compileOnly | ✅ | ❌ | ❌ | 注解处理器等 |
runtimeOnly | ❌ | ✅ | ❌ | 数据库驱动等 |
testImplementation | ✅(测试) | ✅(测试) | ❌ | 单元测试 |
implementation vs api
implementation 不传递依赖,模块 B 依赖模块 C 用 implementation,则依赖模块 B 的模块 A 无法直接使用 C 的 API。这有利于编译隔离,api 变更时只重编 B 不重编 A。
Version Catalog(推荐)
gradle/libs.versions.toml
[versions]
kotlin = "1.9.22"
compose-bom = "2024.02.00"
okhttp = "4.12.0"
[libraries]
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
[plugins]
android-application = { id = "com.android.application", version = "8.2.2" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
app/build.gradle.kts
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.okhttp)
implementation(platform(libs.compose.bom))
}
自定义 Task
build.gradle.kts
tasks.register("printVersionName") {
// 配置阶段
val versionName = android.defaultConfig.versionName
doLast {
// 执行阶段
println("VersionName: $versionName")
}
}
// Task 依赖
tasks.register("release") {
dependsOn("assembleRelease", "printVersionName")
}
常见面试问题
Q1: implementation 和 api 的区别是什么?什么时候用 api?
答案:
implementation 的依赖不会传递给上层模块,api 的依赖会传递。
使用 api 的场景:当模块 B 的公开 API(方法参数、返回值)中使用了模块 C 的类型时,B 应该用 api 依赖 C,否则上层模块 A 编译时找不到 C 的类型。
优先使用 implementation,因为它减少了编译时的依赖传递,C 的变更只触发 B 重编,不会触发 A 重编,编译速度更快。
Q2: Gradle 的三个构建阶段分别做什么?
答案:
- 初始化阶段:解析
settings.gradle,确定哪些项目(include)参与本次构建 - 配置阶段:执行所有参与项目的
build.gradle脚本,注册 Task 并构建 Task 的有向无环图(DAG) - 执行阶段:根据命令行指定的 Task,按照 DAG 依赖顺序执行相关 Task 的
doFirst/doLast动作
常见问题是在配置阶段执行了耗时操作(如读取文件、网络请求),导致每次构建都变慢。应将耗时逻辑放在 doLast 中。