Task类型与自定义:Gradle内置Task类型与自定义Task类
说实话,刚开始学Gradle的时候,我对Task的理解特别肤浅。就觉得Task嘛,不就是一段脚本,跑一下就完事了。后来在项目里踩了不少坑,才慢慢摸清楚这里面的门道。今天咱们就好好聊聊Gradle里的Task类型,以及怎么自定义自己的Task。
Gradle内置的Task类型
Gradle给我们准备了好几种现成的Task类型。我个人觉得,用好这些内置类型,能省下不少重复造轮子的时间。咱们挑几个最常用的来说说。
Copy类型
这个我用的最多。说白了就是复制文件用的。我在项目里经常用它来把构建产物复制到指定目录。
tasks.register('copyApk', Copy) {
from layout.buildDirectory.dir("outputs/apk/debug")
into layout.buildDirectory.dir("myApks")
include "**/*.apk"
exclude "**/*-unaligned.apk"
}
嗯,这里要注意一点:from和into的路径写法。我刚开始用的时候,直接写字符串路径,结果在不同机器上老是出问题。后来改用layout.buildDirectory这种Project提供的API,就稳多了。
Delete类型
删除文件或目录用的。这个其实挺简单,但有个坑我得提醒你。
tasks.register('cleanTemp', Delete) {
delete layout.buildDirectory.dir("temp")
// 注意:这里不会删除项目根目录下的文件!
}
我曾经犯过一个错误:想删除项目根目录下的某个文件夹,结果写成了delete "build/temp"。你猜怎么着?它删的是当前工作目录下的,不是项目根目录。后来我学乖了,一律用layout.projectDirectory来定位。
Exec类型
执行系统命令用的。这个在需要调用外部工具时特别有用。
tasks.register('runLint', Exec) {
workingDir = layout.projectDirectory.asFile
commandLine 'lint', '--check', 'all'
// 或者用executable + args的方式
executable 'lint'
args '--check', 'all'
}
我个人习惯用commandLine,因为写起来更直观。但要注意,如果命令路径包含空格,最好用commandLine的列表形式,别用字符串拼接。
自定义Task类
内置类型虽然方便,但有时候我们需要更复杂的逻辑。这时候就得自己写Task类了。
自定义Task类有两种方式:一种是在build.gradle.kts里直接写,另一种是单独写一个类文件。我建议你,如果逻辑超过20行,就单独写个类文件,不然build脚本会变得又臭又长。
abstract class MyCustomTask : DefaultTask() {
@get:Input
abstract val inputFile: DirectoryProperty
@get:Output
abstract val outputFile: RegularFileProperty
@TaskAction
fun process() {
val input = inputFile.get().asFile
val output = outputFile.get().asFile
logger.lifecycle("开始处理: ${input.name}")
// 这里写你的业务逻辑
input.readLines().forEach { line ->
output.appendText("处理后的: $line\n")
}
logger.lifecycle("处理完成: ${output.name}")
}
}
看到@TaskAction了吗?这个注解告诉Gradle:这个方法就是Task要执行的核心逻辑。没有这个注解,Gradle不知道你的Task该干啥。
@TaskAction注解的细节
这个注解其实挺讲究的。一个Task类里可以有多个@TaskAction方法吗?答案是:不行。Gradle只认一个。
注意:@TaskAction方法必须是public的,不能有返回值(void),也不能有参数。如果你需要传参数,用属性(Property)的方式。
我曾经看到有人这么写:
// 错误示范
@TaskAction
fun process(input: String): Boolean {
// 这样写会报错!
}
嗯,这样写Gradle会直接给你抛异常。正确的做法是把输入输出都声明为属性。
Task的group与description
这两个属性看着简单,但用好了能让你的构建脚本清晰很多。
| 属性 | 作用 | 示例 |
|---|---|---|
| group | Task所属的分组,用于在任务列表中归类 | "build", "verification", "myCustom" |
| description | Task的描述,方便其他人理解 | "生成APK并复制到指定目录" |
tasks.register('myTask') {
group = "myCustom"
description = "这是我自定义的任务,用于处理一些特殊逻辑"
doLast {
// 任务逻辑
}
}
你想想看,如果项目里有几十个Task,没有group和description,别人怎么知道哪个是干嘛的?我见过一个项目,所有Task的group都是空的,description也是空的。每次新人来了都得问:"这个task是干啥的?" 后来我花了一天时间,把所有Task的group和description都补上了。从那以后,团队效率提升了不少。
知识体系总览
下面这张图帮你理清今天讲的内容:
小技巧:在命令行里运行 gradle tasks --group="myCustom" 可以只看某个分组的Task。这个命令我几乎天天用,特别是在项目Task特别多的时候。
好了,今天的内容就到这里。记住,Task是Gradle构建的核心,用好内置类型能省力,自定义Task能解决复杂需求,而group和description则是让代码更易维护的关键。下次咱们聊聊Task的依赖关系和执行顺序,这个在大型项目里特别重要。
公众号:蓝海资料掘金营,微信deep3321