一、前言
只有 Task 才可以在 Gradle 的执行阶段去执行(其实质是执行的 Task 中的一系列 Action),所以 Task 的重要性不言而喻。
二、Task
2.1 Task 定义与配置
Task 的定义方式有如下两种:
Task 的配置方式也有如下两种:
配置了 group 后可以在 Android Studio 的 Gradle 面板看到对应的 Task Group 及其分组下的 Tasks,如下图所示:
一般来说都推荐为我们的 task 配置 group,便于我们查找 task。另外,group 和 descreption 只是最基本的配置,我们看下 Task 的源码:
可以看到这些属性都是可以进行配置的,后面会一一讲解。
选型 | 描述 | 默认值 |
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,我们来执行其中一个:
看到上述输出我们会有个疑问,为什么我们执行 helloTask2,但是 helloTask 也被执行输出了呢?其实很简单,因为这两个 task 都是在 gradle 配置阶段执行的,所以我们任何 task 的执行,我们 project 的整个配置代码都是会执行的,所以这两个输出语句都会被执行到。
我们可以通过添加 doFirst 与 doLast 执行动作(Action)为我们的 task 指定执行阶段要执行的代码,这样它就只会在 gradle 执行阶段去执行。需要注意的是,doFirst 和 doLast 是可以被执行多次的。对于 doFirst 与 doLast 这两个 Action,它们的作用分别如下所示:
- doFirst:表示 task 执行最开始的时候被调用的 Action。
- doLast:表示 task 将执行完的时候被调用的 Action。
我们来验证下:
接下来,我们就使用 doFirst 与 doLast 来进行一下实战,来实现计算 build 执行期间的耗时,其完整代码如下所示:
2.3 Task 执行顺序
指定 Task 的执行顺序有三种方式,如下图所示:
2.3.1 dependsOn 强依赖方式
dependsOn 强依赖的方式可以细分为静态依赖和动态依赖,首先看看静态依赖,如下所示:
taskZ 依赖 taskX 和 taskY:
执行 taskZ 看看:
可以看到被依赖的 task 先执行,这和我们 java 的继承关系是很相似的。需要注意的是,这里 taskX 和 taskY 的执行顺序是随机的。
下面我们再来看看动态依赖:
2.3.2 通过Task输入输出指定
我们也可以通过 Task 来指定输入输出,Task 的输入输出对应 TaskInput 和 TaskOutput。下面我们来看一个示例,使用这种方式实现一个自动维护版本发布文档的 gradle 脚本,其中输入输出相关的代码如下所示:
首先,我们定义了一个 WirteTask,然后,在注释1处,指定了输出文件为 destFile, 并写入版本信息到 XML 文件。接着,定义了一个 readTask,并在注释2处,指定输入文件为上一个 task(即 writeTask) 的输出文件。最后,在注释3处,使用 dependsOn 将这两个 task 关联起来,此时输入与输出的顺序是会先执行写入,再执行读取。这样,一个输入输出的实际案例就实现了。
2.3.3 通过API指定执行顺序
除了 dependsOn 的方式,我们还可以在 task 闭包中通过 mustRunAfter 方法指定 task 的依赖顺序,mustRunAfter 可以指定一个或多个 task,其示例代码如下所示:
下面我们在命令行中将 taskX、taskY、taskZ 打乱执行:
可以看到最终的执行顺序始终是 taskX、taskY、taskZ。
mustRunAfter 是强制指定顺序,另外还有一个 shouldRunAfter 不强制性指定,实际应用中一般不会使用 shouldRunAfter,了解一下即可。
2.4 挂接自定义 task 到构建生命周期
我们可以使用 gradle 提供的一系列生命周期 API 去挂接我们自己的 task 到构建生命周期之中,比如使用 afterEvaluate 方法将我们第三小节定义的 writeTask 挂接到 gradle 配置完所有的 task 之后的时刻,示例代码如下所示:
2.5 Task 类型
除了定义一个新的 task 之外,我们也可以使用 task 的 type 属性来直接使用一个已有的 task 类型,比如 Gradle 自带的 Copy、Delete、Sync task 等等。示例代码如下所示:
更多的 Task 类型我们可以查阅官方文档。