1.Gradle 的 Project 从本质上说只是含有多个 Task 的容器,一个 Task 与 Ant 的 Target 相似,表示一个逻辑上的执行单元。我们可以通过很多种方式定义 Task,所有的 Task 都存放在 Project 的 TaskContainer 中。
2.Task 可以理解为 Gradle 的执行单元,实在是太重要了。根据前面的分析,Gradle 通过一个个 task 来完成具体的构建任务,下面我们来看下 Task 的定义。
(1)调用 Project 的 task() 方法创建 Task
在使用 Gradle 时,创建 Task 最常见的方式便是:
- task helloWord << {
- println 'Hello World! Charles'
- }
- 这里的" << "表示追加的意思,即向hello中加入执行过程。我们还可以使用doLast来达到同样的效果:
- task hello2 {
- doLast {
- println 'hello2'
- }
- }
- 另外,如果需要向Task的最前面加入执行过程,我们可以使用doFirst:task hello3 {
- doFirst {
- println 'hello3'
- }
- }
- 除此之外,doLast还有一个等价的操作leftShift,leftShift还可以缩写为 << ,因此下这三种实现效果等价helloWord.leftShift {
- println 'Hello World! Charles--left'
- }
在上面的例子中,Gradle 的 DSL 向我们展示了一种非常自然的风格来创建 Task,而事实上这些都只是一种内部 DSL,也即必须符合 groovy 的语法要求。上面的 task 关键字实际上是一个方法调用,该方法属于 Project。Project 中存在多个重载的 task() 方法。和 Ruby 等动态语言一样,在调用 groovy 方法时,我们不用将参数放在括号里面。
以上我们自定义的 Task 都位于 TaskContainer 中,Project 中的 tasks 属性即表示该 TaskContainer。为此,我们可以新建一个 Task 来显示这些信息:
- task showTasks {
- println tasks.class
- println tasks.size()
- }
将以上 4 个 Task 放在同一个 build.gradle 中,再执行 gradle showTasks,命令行输出如下:
- ...
- class org.gradle.api.internal.tasks.DefaultTaskContainer_Decorated
- 4
- ...
上面的 DefaultTaskContainer_Decorated 表示 tasks 类型,而 4 表示该 TaskContainer 中包含有 4 个自定义的 Task——包括 showTasks 本身。
(2) 通过 TaskContainer 的 create() 方法创建 Task 而 Project 又维护了一个 TaskContainer 类型的属性 tasks,那么我们完全可以直接向 TaskContainer 里面添加 Task。查查 TaskContainer 的 API 文档可以发现,TaskContainer 向我们提供了大量重载的 create() 方法用于添加 Task。
- tasks.create(name: 'hello4') << {
- println 'hello4'
- }
(3) 声明 Task 之间的依赖关系
Task 之间是可以存在依赖关系,比如 TaskA 依赖 TaskB,那么在执行 TaskA 时,Gradle 会先执行 TaskB,再执行 TaskA。我们可以在定义一个 Task 的同时声明它的依赖关系:
- task hello5(dependsOn: hello4) << {
- println 'hello5'
- }
当然,我们也可以在定义 Task 之后再声明依赖:
- task hello6 << {
- println 'hello6'
- }
- hello6.dependsOn hello5
(4) 配置 Task
一个 Task 除了执行操作之外,还可以包含多个 Property,其中有 Gradle 为每个 Task 默认定义的 Property,比如 description,logger 等。另外,每一个特定的 Task 类型还可以含有特定的 Property,比如 Copy 的 from 和 to 等。当然,我们还可以动态地向 Task 中加入额外的 Property。在执行一个 Task 之前,我们通常都需要先设定 Property 的值,Gradle 提供了多种方法设置 Task 的 Property 值。
首先,我们可以在定义 Task 的时候对 Property 进行配置:
- task hello7 << {
- description = "this is hello7"
- println description
- }
我们还可以通过闭包的方式来配置一个已有的 Task:
- task hello8 << {
- println description
- }
- hello8 {
- description = "this is hello8"
- }
需要注意的是,对 hello8 的 description 设置发生在创建该 Task 之后,在执行 "gradle hello8" 时,命令行依然可以打印出正确的 "this is hello8",这是因为 Gradle 在执行 Task 时分为两个阶段,首先是配置阶段,然后才是实际执行阶段。所以在执行 hello8 之前,Gradle 会扫描整个 build.gradle 文档,将 hello8 的 description 设置为 "this is hello8",然后执行 hello8,此时 hello8 的 description 已经包含了设置后的值。
我们还可以通过调用 Task 的 configure() 方法完成 Property 的设置:
- task hello9 << {
- println description
- }
- hello9.configure {
- description = "this is hello9"
- }
实际上,通过闭包的方式配置 Task 在内部也是通过调用 Task 的 configure() 方法完成的
(5)group task 属于哪个组下面我来看一个列子
- // 定义一个名字为Cls的task,属于Charles分组,并且依赖myTask1和myTask2两个task。
- project.task('ClsTask', group: "charles", description: "我自己的Task", dependsOn: ["myTask1", "myTask2"]).doLast {
- println "execute ClsTask"
- }
尝试执行 gradle ClsTask,结果如下:
- :myTask1
- execute myTask1
- :myTask2
- execute myTask2
- :ClsTask
- execute ClsTask
- BUILD SUCCESSFUL
(6) 定义 Task 的时候是可以指定很多参数的,如下所示:
- 参数 含义 默认值
- name task的名字 不能为空,必须指定
- type task的"父类" DefaultTask
- overwrite 是否替换已经存在的task false
- dependsOn task依赖的task的集合 []
- group task属于哪个组 null
- descriptions task的描述 null
到此 Gradle 定义 Task 就全部讲完。最后,定义 task 的 API 很多,我介绍了最常用的部分,剩下的细节还是需要大家查看 Gradle 文档,其实学习 Gradle 就是一个查文档的过程。如下几个文档,大家读读。
Project API
来源: http://www.jianshu.com/p/3e64dcb3a5b2