跳到主要内容

Gradle 构建基础

问题

Gradle 的核心概念有哪些?Android 项目的 Gradle 构建流程是怎样的?

答案

Gradle 核心概念

概念说明
Project每个 build.gradle 对应一个 Project,根项目负责全局配置
Task构建的最小执行单元,如 compileKotlinassembleDebug
Plugin扩展 Gradle 功能,如 com.android.applicationkotlin-android
Configuration依赖作用域:implementationapicompileOnly
Build Scriptbuild.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 的三个构建阶段分别做什么?

答案

  1. 初始化阶段:解析 settings.gradle,确定哪些项目(include)参与本次构建
  2. 配置阶段:执行所有参与项目的 build.gradle 脚本,注册 Task 并构建 Task 的有向无环图(DAG)
  3. 执行阶段:根据命令行指定的 Task,按照 DAG 依赖顺序执行相关 Task 的 doFirst/doLast 动作

常见问题是在配置阶段执行了耗时操作(如读取文件、网络请求),导致每次构建都变慢。应将耗时逻辑放在 doLast 中。

相关链接