任务系统基础
源:Gradle 官方文档 - More about Tasks | Tutorial Using Tasks
任务(Task)是 Gradle 构建的核心,理解任务系统是掌握 Gradle 的关键。
任务概念
什么是任务
任务是 Gradle 中最小的执行单元,代表构建过程中的一个独立操作。
示例:
- 编译源代码
- 运行测试
- 打包 APK
- 上传到服务器
任务的组成
任务配置:
- 名称
- 描述
- 分组
- 依赖关系
任务动作:
- doFirst {}
- doLast {}
- TaskAction
查看任务
列出所有任务
bash
# 列出所有任务
./gradlew tasks
# 显示所有任务(包括隐藏的)
./gradlew tasks --all输出示例:
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
clean - Deletes the build directory.
Verification tasks
------------------
check - Runs all checks.
test - Runs the test suite.查看特定组的任务
bash
./gradlew tasks --group=build
./gradlew tasks --group=verification查看任务详情
bash
./gradlew help --task <taskName>
# 示例
./gradlew help --task assemble常用内置任务
Android 构建任务
编译任务:
bash
# 编译 Debug 版本
./gradlew assembleDebug
# 编译 Release 版本
./gradlew assembleRelease
# 编译所有变体
./gradlew assemble打包任务:
bash
# 生成 AAB
./gradlew bundleRelease
# 生成 APK
./gradlew assembleRelease清理任务
bash
# 清理 build 目录
./gradlew clean
# 清理特定模块
./gradlew :app:clean测试任务
bash
# 运行单元测试
./gradlew test
# 运行 Android 插桩测试
./gradlew connectedAndroidTest
# 运行特定测试
./gradlew :app:testDebugUnitTest代码质量任务
bash
# Lint 检查
./gradlew lint
# 生成 Lint 报告
./gradlew lintDebug依赖任务
bash
# 查看依赖树
./gradlew dependencies
# 查看特定配置
./gradlew :app:dependencies --configuration implementation
# 依赖洞察
./gradlew dependencyInsight --dependency <name>创建 Ad-hoc 任务
简单任务
kotlin
// build.gradle.kts
tasks.register("hello") {
doLast {
println("Hello, Gradle!")
}
}执行:
bash
./gradlew hello带配置的任务
kotlin
tasks.register("greet") {
group = "custom"
description = "打印问候语"
doLast {
println("Hello from Gradle!")
}
}doFirst 和 doLast
kotlin
tasks.register("sequence") {
doFirst {
println("First")
}
doLast {
println("Last")
}
doFirst {
println("Another First")
}
}执行顺序:
> Task :sequence
Another First
First
Last任务依赖
dependsOn
kotlin
tasks.register("taskA") {
doLast {
println("Task A")
}
}
tasks.register("taskB") {
dependsOn("taskA")
doLast {
println("Task B")
}
}执行 taskB:
bash
./gradlew taskB输出:
> Task :taskA
Task A
> Task :taskB
Task B多个依赖
kotlin
tasks.register("taskC") {
dependsOn("taskA", "taskB")
doLast {
println("Task C")
}
}finalizedBy
kotlin
tasks.register("main") {
doLast {
println("Main task")
}
}
tasks.register("cleanup") {
doLast {
println("Cleanup")
}
}
tasks.named("main") {
finalizedBy("cleanup")
}执行:
bash
./gradlew main输出:
> Task :main
Main task
> Task :cleanup
CleanupmustRunAfter / shouldRunAfter
mustRunAfter:
kotlin
tasks.register("taskX") {
doLast {
println("Task X")
}
}
tasks.register("taskY") {
mustRunAfter("taskX")
doLast {
println("Task Y")
}
}执行:
bash
./gradlew taskY taskX输出:
> Task :taskX
Task X
> Task :taskY
Task YshouldRunAfter(软约束):
kotlin
tasks.register("taskZ") {
shouldRunAfter("taskX")
doLast {
println("Task Z")
}
}任务输入输出
声明输入
kotlin
abstract class ProcessFileTask : DefaultTask() {
@get:InputFile
abstract val inputFile: RegularFileProperty
@TaskAction
fun process() {
val content = inputFile.get().asFile.readText()
println("Processing: $content")
}
}
tasks.register<ProcessFileTask>("processFile") {
inputFile.set(file("input.txt"))
}声明输出
kotlin
abstract class GenerateFileTask : DefaultTask() {
@get:OutputFile
abstract val outputFile: RegularFileProperty
@TaskAction
fun generate() {
outputFile.get().asFile.writeText("Generated content")
}
}
tasks.register<GenerateFileTask>("generateFile") {
outputFile.set(layout.buildDirectory.file("output.txt"))
}输入输出注解
| 注解 | 用途 |
|---|---|
| @Input | 简单值输入 |
| @InputFile | 单个文件输入 |
| @InputFiles | 多个文件输入 |
| @InputDirectory | 目录输入 |
| @Output | 简单值输出 |
| @OutputFile | 单个文件输出 |
| @OutputFiles | 多个文件输出 |
| @OutputDirectory | 目录输出 |
增量构建
UP-TO-DATE 检查
条件:
- 输入未改变
- 输出存在
- 任务代码未改变
示例:
kotlin
abstract class CopyTask : DefaultTask() {
@get:InputFile
abstract val source: RegularFileProperty
@get:OutputFile
abstract val destination: RegularFileProperty
@TaskAction
fun copy() {
source.get().asFile.copyTo(
destination.get().asFile,
overwrite = true
)
}
}
tasks.register<CopyTask>("copyFile") {
source.set(file("src.txt"))
destination.set(file("dest.txt"))
}首次运行:
> Task :copyFile再次运行:
> Task :copyFile UP-TO-DATE任务禁用
禁用任务
kotlin
tasks.named("test") {
enabled = false
}条件禁用
kotlin
tasks.named("test") {
enabled = !project.hasProperty("skipTests")
}执行:
bash
# 跳过测试
./gradlew build -PskipTests任务超时
设置超时
kotlin
tasks.register("longRunning") {
timeout.set(Duration.ofMinutes(5))
doLast {
// 长时间运行的任务
}
}实战案例
案例1:复制文件
kotlin
tasks.register<Copy>("copyResources") {
from("src/resources")
into(layout.buildDirectory.dir("resources"))
}案例2:生成版本文件
kotlin
tasks.register("generateVersionFile") {
val versionFile = layout.buildDirectory.file("version.txt")
outputs.file(versionFile)
doLast {
versionFile.get().asFile.writeText("Version: ${project.version}")
}
}案例3:修改 APK 名称
kotlin
// 使用新的 Variant API(AGP 7.0+)
androidComponents {
onVariants { variant ->
variant.outputs.forEach { output ->
output.versionName.set("${variant.name}-${project.version}")
}
}
}案例4:打包前检查
kotlin
tasks.register("prePackageCheck") {
doLast {
val requiredFile = file("required.txt")
if (!requiredFile.exists()) {
throw GradleException("Required file not found: $requiredFile")
}
}
}
tasks.named("assembleRelease") {
dependsOn("prePackageCheck")
}最佳实践
使用 register 而非 create:
- 延迟创建
- 提升配置性能
声明输入输出:
- 支持增量构建
- 支持缓存
- 提升性能
避免配置阶段操作:
- 使用 doLast
- 使用 Provider API
使用类型化任务:
- 重用性好
- 类型安全
- 易于维护
合理使用依赖:
- dependsOn:必需依赖
- finalizedBy:清理任务
- mustRunAfter:顺序控制
设置 group 和 description:
- 便于查找
- 易于理解
- 团队协作
处理任务失败:
kotlin
tasks.register("mayFail") {
doLast {
try {
// 可能失败的操作
} catch (e: Exception) {
logger.error("Task failed: ${e.message}")
throw e
}
}
}