Gradle学习笔记-Task
Gradle的两个重要的概念:
Project
和Task
,一个Project
由多个Task
组成。
Task
Gradle脚本中的最小执行单元,也是Gradle中的一个原子操作。
Task Result(任务结果)
当Task执行时,最终控制台都会输出执行的结果,后面都会带有一个标签,这些标签表示了是否有Task需要执行,是否执行了Task等状态。
结果标签 | 结果描述 | 如何触发 |
---|---|---|
没有标签 EXECUTED |
任务执行完毕 | 任务有动作且被执行 |
UP-TO-DATE | 任务输出没有改变 | 任务没有动作也没有依赖 任务有输入输出但是没有发生变化 任务没有动作但存在依赖,且依赖非执行完毕 |
NO-SOURCE | 任务不需要执行 | 包含了输入输出,但是没有Sources??? |
FROM-CACHE | 在缓存中找到了任务执行结果 | 构建缓存中已存在构建结果 |
SKIPPED | 任务没有执行 | 指定跳过该任务 任务设置了 onlyIf 且返回false任务被禁用 enabled=false |
Task Create(创建任务)
1 |
|
其中
<<
等价于doLast
,但是在Gradle 5.0
之后该方法已被废弃。
上述只是基础的创建方法,创建时还包括了其他的参数。
参数名 | 含义 | 参数属性 |
---|---|---|
name | 任务名称 | 必须有值,不能为空 |
description | 任务描述 | 可以为空 |
group | 任务所属分组名 | 可以为空 |
type | 任务的父类 | 默认为org.gradle.api.DefaultTask |
dependsOn | 任务依赖的其他Task | 可以为空 |
overwrite | 是否覆盖已存在的同名任务 | false |
constructorArgs | 任务构造函数参数 | 可以为空(若依赖父类有构造参数,需要设置值) |
action | 任务的顺序执行序列 | doLast(最后执行) 、doFirst(最先执行) |
Task Action(执行序列)
一个
Task
由一系列Action
组成的,通过设置action
,实质上就是在创建Task时调用到的doFirst
、doLast
这两个方法。
1 |
|
上述代码不同的执行方式结果不同
执行整个
gradle
文件:1
Task configure
执行
Task1
:./gradlew Task1
1
2
3Task configure
Task doFirst
Task doLast
观察上述结果,得出以下结论
在创建Task时,除了
doFirst
、doLast
之外的代码,都定义为Task
的配置项,在脚本的配置阶段都会执行;而doFirst
、doLast
代码只会在Task
真正执行时才会调用(gradle 指定运行该Task
)。
Task DependsOn(执行依赖)
Gradle中的任务执行顺序是不确定的,需要通过task之间的依赖关系,保证被依赖的task优先执行,可通过
dependsOn
来确定依赖关系。默认规则与Task名称相关,按照名称进行排序!
dependsOn 强依赖
1 |
|
此时调用./gradlew third
1 |
|
由于third
依赖于first、second
所以在执行third
时,first、second
也需要执行。
以上属于静态依赖。
相对的还存在动态依赖。
1 |
|
顺序依赖
此外可通过
shouldRunAfter
和mustRunAfter
来控制任务之间的执行顺序
mustRunAfter
强制按照要求的顺序执行
shouldRunAfter
非强制的按照顺序执行,在以下两种情况会放弃此规则:
TaskGraph
为有向无环,可能导致环形放弃规则- 并行执行任务并且所有任务的依赖项都已完成
Task Type(任务类型)
默认Type为
DefaultTask
,系统还提供了几种常用的类型以供使用,也可以通过自定义Type来实现功能。
Copy
将文件复制到目标目录,此任务在复制时也可以执行重命名和过滤文件操作。
1 |
|
from
、into
是最基础的配置,其他常用包括以下:
配置项 | 释义 | 示例 |
---|---|---|
include | 只包含配置的文件 | include '**/*.java', '**/*.kt' |
exclude | 排除配置的文件 | exclude '**/*.xml' |
includeEmptyDirs | 是否包括空文件夹 | true 文件夹下的所有文件夹也会被拷贝进来false 不会存在空文件夹 |
rename | 对指定的文件进行重命名 | rename 'activity_*.xml' 'rename' |
with | 执行一个闭包 | def dataContent = copySpec { from (‘../src/main’) { include ‘*/.xml’ } } with dataContent |
Sync
与Copy任务类似,不同的是将源目录中的文件复制到目标目录中,但是会删除目标目录中非复制过来的文件。
1 |
|
可通过设置preverse
属性,控制哪些文件不会被覆盖
1 |
|
那么目标目录原有的xml
不会被删除
其他类型
通过官网介绍来查询其他系统支持类型
自定义Type
1 |
|
Task Group(任务分组)&Task Description(任务描述)
对任务进行分组整理,使结构清晰明了
对任务进行描述,说明任务的作用
1 |
|
可以通过执行./gradlew -q tasks --all
查看所有task信息
1 |
|
Task Overwrite(任务重写)
对上面的任务进行覆盖,后续只会执行该任务
1 |
|
后续只会输出Cover Same Task
Task Enable(任务启用)
通过设置
enabled
属性,用于启用和禁用任务,默认为true
,表示启用。false
则禁止该任务执行
1 |
|
运行会提示 Task :plugin:zipFile SKIPPED
TaskContainer(任务集合)
管理所有的Task实例,可通过
Project.getTasks()
或者tasks
使用该实例
提供了以下常用的方法
方法 | 介绍 |
---|---|
create(name:String) : Task |
创建任务 |
create(name:String,configureClosure:Closure) : Task |
创建任务 |
create(options: Map<String, ?>,configure: Closure): Task |
创建任务 |
findByPath(path: String): Task |
查找任务 |
getByName(name: String): Task |
根据Task名字查找任务 |
withType(type: Class): TaskCollection |
根据Type查找任务 |
register(String name):TaskProvider |
按需加载任务 |
replace(String name):Task |
替换当前同名任务 |
remove(Task task) |
删除任务 |
whenTaskAdded(action:Closure) |
task添加进TaskContainer时监听 |
1 |
|
Task增量构建
Task会缓存每次运行的结果,在下次运行时会检查输出结果是否进行改变,没有发生变化就会跳过当次运行 。为了提高Gradle的编译速度。
在控制台会显示
up-to-date
表示跳过该次执行。
Gradle通过对比上一次构建之后,Task的inputs和outputs是否发生变化,来决定是否跳过执行。
Task Input/Output(任务输入/输出)
大多数情况下,
Task
需要接收一些Input(输入)
,并生成一些Output(输出)
。
上图是一个简单的示例:
通过Input——TargetJDKVersion , Sourcefiles
经过JavaCompileTask
处理后得到Output——Class files
。
可以将其理解为一个函数,
input
为入参,output
为返回值。还有两个关键点:
- 隐式依赖:若Task的输入为另一Task的输出,则会被推断出依赖关系。
- 配置阶段声明
在定义Task的输入输出时,要遵循一个原则:只有Task的属性会影响输出,就需要把该属性注册为输入。
1 |
|
以上定义了三个Task:
- writeTask:写入
release.xml
,出参为release.xml
路径 - zreadTask:读取
release.xml
,此时zreadTask
与writeTask
建立了隐式依赖 - IOFinishTask:执行需要依赖
zreadTask
与writeTask
第一次执行IOFinishTask
时,会执行zreadTask
与writeTask
,再次执行时,writeTask
标记为up-to-date
,表示为增量构建。
Task-Input
Task-Input有三种形式的输入:
- 简单值:包括数值(int)、字符串(String)和任何实现Serializable的类。 @Input
- 文件:包括单个文件或文件目录 @InputFile @InputDirectory @InputFiles
- 嵌套对象:非以上两种输入,内部含有嵌套的
inputs
和outputs
类型 @Nested
Task-Output
Task-Output输出主要为:
- 文件:包括文件或文件目录 @OutputFile @OutputDirectory
运行时API
可以通过
Runtime API
在自定义Task时使用增量构建。相比与自定义Task类
可以减少改动成本。
Runtime API主要有三个:
- Task.getInputs
- property/proprtrties == @Input
- file/files == @InputFile/@InputFiles
- dir == @InputDirectory
- Task.getOutputs
- files/file = @OutputFiles/@OutputFile
- dirs/dir = @OutputDirectories/@OutputDirectory
- Task.getDestroyables
1 |
|
输入校验
Gradle会默认对
@InputFile、@InputDirectory、@OutputDirectory
进行为空校验,若需要变为可选需要使用@Optional
Task Other
onlyIf
断言
onlyIf
接收一个闭包作为参数,若闭包中返回true
则执行任务,否则跳过该任务(SKIPPED
)。主要用于控制任务的执行场景。
1 |
|
命令行中输入./gradlew testOnlyIf -Pskip=true
则提示Task :testOnlyIf SKIPPED
。设置-Pskip=false
则输出testOnlyIf run
。
命令行中
-P
表示为Project
指定K-V
格式的属性键值对,使用格式为-PK=V
finalizer
任务
监听任务结束状态,可以在结束后执行其他任务
1 |
|
./gradlew taskx -q
运行结果为
1 |
|
Finalizer
即使运行过程中出现异常也不会影响到后续任务的执行,只有一种情况下会出现无法执行后续任务。当前置任务根本没有执行时,不会触发后续任务执行。
判断正在执行的任务
监听正在执行的任务,触发需要监听的任务时,执行功能
1 |
|
挂载自定义Task在构建过程
在其他
Task
执行过程中,调用自定义Task
的execute
1 |
|
引用
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!