有道无术,术尚可求,有术无道,止于术。
在Gradle 中,任务是最小执行单元,一个build.gradle
是由一系列的任务组成。每个项目都由不同的任务组成。任务是构建执行的一项工作。任务可以是编译一些类,将类文件存储到单独的目标文件夹中,创建JAR,生成Javadoc或将一些归档发布到存储库。
task
是用于将任务定义到构建脚本中的关键字。
比如我们定义一个任务,然后在工具栏中就可以执行,和Maven 中的目标一样,就是一个功能。
一些常见创建任务的方式如下所示:
// 1. 定义一个任务
task hello {
println 'hello world'
}
// 2. 使用参数定义任务名
task('task001') {
println "task001"
}
// 3. 使用tasks 集合对象创建任务
tasks.create("task002") {
println "task002"
}
// 4. 使用project获取tasks 集合对象创建任务
project.getTasks().create("task003") {
println "task003"
}
// 5. 向tasks 集合中注册任务,被使用时才会创建
tasks.register('task004') {
println 'task004'
}
还可以在添加任务的时候对其进行分组,比如:
task taskDev1{
// 分组到dev
group "dev"
description "项目描述"
println "method1"
}
task('taskDev2'){
// 分组到dev
group "dev"
println "method2"
}
分组后,在工具栏任务列表就可以看到:
创建的任务都放在了TaskContainer
对象统一管理。
TaskContainer
常用定位任务方法如下所示:
// 1. 根据任务名查询任务,没有抛出NULL
println tasks.findByPath('task004').path
println tasks.findByPath('task005').path
// 2. 根据任务名查询任务,没有抛出UnknownTaskException
println tasks.getByPath('task004').path
println tasks.getByPath(':task005').path
一个任务包含若干Action
,Gradle提供了doLast()
和doFirst()
函数,用于在执行任务时最新执行和最后执行的Action
。
实例如下:
task taskFirstLast{
println "taskFirstLast"
doLast{
println "last"
}
doFirst{
println "first"
}
group "dev"
}
也可以使用如下方式编写:
task taskFirstLast {
println "taskFirstLast"
}
myTask.doFirst {
println "first"
}
myTask.doLast {
println "last"
}
定义Task的时候是可以指定很多参数的,如下所示:
参数 | 含义 | 默认值 |
---|---|---|
name | task的名字 | 不能为空,必须指定 |
type | task的“父类” | DefaultTask |
overwrite | 是否替换已经存在的task | false |
dependsOn | task依赖的task的集合 [] | |
group | task属于哪个组 | null |
description | task的描述 | null |
可以通过以下两种方式定义有参数的任务:
task task001{
}
task task002{
}
// 1. 定义有参任务方式1
project.task('task006', group: "dev", description: "有参任务", dependsOn: ["task001", "task002"] ) {
println "task006"
}
// 2. 定义有参任务方式2
task task007 {
group "dev"
description "有参任务"
dependsOn task001, task002
doLast {
println "task007"
}
}
创建任务的时候可以通过type: SomeType
指定Type,Type其实就是告诉Gradle,这个新建的Task对象会从哪个基类Task派生。
Gradle本身提供了一些通用的Task,最常见的有Copy
任务,还提供了其他如Delete
、Sync
等。
下面示例中是一个简单的Copy 任务:
// 创建任务,派生自Copy, 可以实现复制文件
task copyDocs(type: Copy) {
from 'src/main/doc' // 被复制的文件
into 'build/target/doc' // 目标
}
Copy
的时候还可以进行重命名:
task chVer(type: Copy) {
from "src/main/manifest/AndroidManifestCopy.xml" // 复制src/main/manifest/目录下的AndroidManifest.xml
into 'src/main' // 复制到指定目标目录
rename { String fileName -> //在复制时重命名文件
fileName = "AndroidManifest.xml" // 重命名
}
}
Copy
还可以配置复制规则闭包、过滤、重命名等:
// 这是个Ant filter
import org.apache.tools.ant.filters.ReplaceTokens
// 创建一个复制规则闭包
def copyRule = copySpec {
from 'src/data'
include '*.data'
}
task initConfig(type: Copy) {
from('src/main/config') {
include '**/*.properties'
include '**/*.xml'
filter(ReplaceTokens, tokens: [version: '2.3.1']) // 过滤
}
from('src/main/config') {
exclude '**/*.properties', '**/*.xml'
}
from('src/main/languages') {
rename 'EN_US_(.*)', '$1' // 重命名
}
into 'build/target/config'
exclude '**/*.bak' // 排查文件
includeEmptyDirs = false // 是否包含空文件夹
with copyRule // 引用规则
}
其他的一些任务类型如下所示:
任务 | 描述 |
---|---|
Copy | 将文件复制到目标目录 |
Delete | 删除文件和目录 |
Exec | 执行命令行程序 |
GradleBuild | 执行Gradle构建 |
JavaExec | 在一个子进程中执行一个Java程序 |
Sync | 同步源文件文件或者目录 |
Upload | 将源文件配置的组件上传到执行的仓库 |
还可以通过继承DefaultTask
类自定义类型,如下所示:
class TestTask extends DefaultTask {
// 定义输入参数,任务没有传入或者设置参数,将使用默认参数
@Input
String message = 'TestTask'
// 定义执行方法
@TaskAction
def hello(){
println "Hello:$message"
}
}
// 注册任务,没有传入参数
tasks.register('myTask', TestTask)
// 注册任务,并定义参数值
task hi(type:TestTask){
message ="Hi"
}
任务之间也具有依赖性,通过dependsOn
指定任务名称,就表示依赖其他任务。
同一个工程中建立依赖关系如下所示,执行时,会先执行依赖中的任务,在执行当前任务。
task depends001 {
println 'depends001'
}
task depends002 {
dependsOn depends001
println 'depends002'
}
如果依赖其他项目的任务,按照如下写法:
project('project-a') {
task taskX {
dependsOn ':project-b:taskY' // 依赖其他项目的任务
doLast { println 'taskX' }
}
}
任务是可以进行排序的,通过这种方式可以在某些情况下控制任务的执行顺序,而不是通过强制依赖的方式。这个功能是非常有用的,比如项目中设置的顺序是必须先执行单元测试,然后才能进行集成测试来保证软件的质量,测速完成后再打包上传发布等操作。
Gradle中有两种排序方式:
如下所示,不过好像执行必须写在doFirst
或者doLast
中才有效。
task order001 {
doFirst{
println "<< order001 doFirst 的打印"
}
}
task order002 {
doFirst{
println "<< order002 doFirst 的打印"
}
}
order001.mustRunAfter order002
//order001.shouldRunAfter order002
可以给任务加上条件判断决定是否执行该任务,onlyIf
表达式为真时,任务才会执行。
task test009 {
doLast { println '=======test009' }
}
// onlyIf 中的表达式为真,才执行任务
test009.onlyIf { !project.hasProperty('avab') }
可以直接设置是否开启任务:
// 是否开启任务,false 表示不开启任务
test009.enabled = false
还可以抛出StopExecutionException
异常,如果遇到这个异常,那么该任务将不会被执行:
task test010 {
doLast { println 'test010' }
}
test010.doFirst {
// 条件判断,抛出异常,该任务后续则不执行
throw new StopExecutionException()
}
task test011 {
dependsOn('test010')
doLast {
println 'test011'
}
}
tasks.addRule
可以定义一些规则:
当执行、依赖一个不存在的任务时,Gradle 会执行失败,提示信息是任务不存在。可以使用规则对其进行修改,让其在执行、依赖不存在的任务时,不会执行失败,而是打印提示信息。代码如下所示:
tasks.addRule("对该规则的一个,便于调试等"){ String taskName ->
task(taskName){
doLast{
println "该 ${taskName} 任务不存在,请查证后再执行"
}
}
}
task taskRule{
dependsOn missTask
}
和java中的finally
一样,task也可以指定对应的最终必须执行的任务,即使上面的任务中抛出了异常。
task taskX {
doLast {
println 'taskX'
}
}
task taskY {
doLast { println 'taskY' }
}
taskX.finalizedBy taskY