暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task

一、前言


只有 Task 才可以在 Gradle 的执行阶段去执行(其实质是执行的 Task 中的一系列 Action),所以 Task 的重要性不言而喻。

 

二、Task


2.1 Task 定义与配置

Task 的定义方式有如下两种:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第1张图片

Task 的配置方式也有如下两种:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第2张图片

配置了 group 后可以在 Android Studio 的 Gradle 面板看到对应的 Task Group 及其分组下的 Tasks,如下图所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第3张图片

一般来说都推荐为我们的 task 配置 group,便于我们查找 task。另外,group 和 descreption 只是最基本的配置,我们看下 Task 的源码:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第4张图片

可以看到这些属性都是可以进行配置的,后面会一一讲解。

选型 描述 默认值
name task 名字 无,必须指定
type 需要创建的 task Class DefaultTask
action 当 task 执行的时候,需要执行的闭包 closure 或 行为 Action null
overwrite 替换一个已存在的 task false
dependsOn 该 task 所依赖的 task 集合 []
group 该 task 所属组 null
description task 的描述信息 null
constructorArgs 传递到 task Class 构造器中的参数 null

 

2.2 Task 执行

上一节我们定义了两个 task,我们来执行其中一个:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第5张图片

看到上述输出我们会有个疑问,为什么我们执行 helloTask2,但是 helloTask 也被执行输出了呢?其实很简单,因为这两个 task 都是在 gradle 配置阶段执行的,所以我们任何 task 的执行,我们 project 的整个配置代码都是会执行的,所以这两个输出语句都会被执行到。

我们可以通过添加 doFirst 与 doLast 执行动作(Action)为我们的 task 指定执行阶段要执行的代码,这样它就只会在 gradle 执行阶段去执行。需要注意的是,doFirst 和 doLast 是可以被执行多次的。对于 doFirst 与 doLast 这两个 Action,它们的作用分别如下所示:

  • doFirst:表示 task 执行最开始的时候被调用的 Action。
  • doLast:表示 task 将执行完的时候被调用的 Action。

我们来验证下:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第6张图片

接下来,我们就使用 doFirst 与 doLast 来进行一下实战,来实现计算 build 执行期间的耗时,其完整代码如下所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第7张图片

 

2.3 Task 执行顺序

指定 Task 的执行顺序有三种方式,如下图所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第8张图片

2.3.1 dependsOn 强依赖方式

dependsOn 强依赖的方式可以细分为静态依赖和动态依赖,首先看看静态依赖,如下所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第9张图片

taskZ 依赖 taskX 和 taskY:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第10张图片

执行 taskZ 看看:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第11张图片

可以看到被依赖的 task 先执行,这和我们 java 的继承关系是很相似的。需要注意的是,这里 taskX 和 taskY 的执行顺序是随机的。

下面我们再来看看动态依赖:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第12张图片

 

2.3.2 通过Task输入输出指定

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第13张图片

我们也可以通过 Task 来指定输入输出,Task 的输入输出对应 TaskInput 和 TaskOutput。下面我们来看一个示例,使用这种方式实现一个自动维护版本发布文档的 gradle 脚本,其中输入输出相关的代码如下所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第14张图片

首先,我们定义了一个 WirteTask,然后,在注释1处,指定了输出文件为 destFile, 并写入版本信息到 XML 文件。接着,定义了一个 readTask,并在注释2处,指定输入文件为上一个 task(即 writeTask) 的输出文件。最后,在注释3处,使用 dependsOn 将这两个 task 关联起来,此时输入与输出的顺序是会先执行写入,再执行读取。这样,一个输入输出的实际案例就实现了。

 

2.3.3 通过API指定执行顺序

除了 dependsOn 的方式,我们还可以在 task 闭包中通过 mustRunAfter 方法指定 task 的依赖顺序,mustRunAfter 可以指定一个或多个 task,其示例代码如下所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第15张图片

下面我们在命令行中将 taskX、taskY、taskZ 打乱执行:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第16张图片

可以看到最终的执行顺序始终是 taskX、taskY、taskZ。

mustRunAfter 是强制指定顺序,另外还有一个 shouldRunAfter 不强制性指定,实际应用中一般不会使用 shouldRunAfter,了解一下即可。

 

2.4 挂接自定义 task 到构建生命周期

我们可以使用 gradle 提供的一系列生命周期 API 去挂接我们自己的 task 到构建生命周期之中,比如使用 afterEvaluate 方法将我们第三小节定义的 writeTask 挂接到 gradle 配置完所有的 task 之后的时刻,示例代码如下所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第17张图片

 

2.5 Task 类型

除了定义一个新的 task 之外,我们也可以使用 task 的 type 属性来直接使用一个已有的 task 类型,比如 Gradle 自带的 Copy、Delete、Sync task 等等。示例代码如下所示:

暴力突破 Gradle 自动化项目构建(六)- Gradle 核心之 Task_第18张图片

更多的 Task 类型我们可以查阅官方文档。

你可能感兴趣的:(Gradle)