Skip to content

任务系统基础

源: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
Cleanup

mustRunAfter / 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 Y

shouldRunAfter(软约束):

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
        }
    }
}