美文网首页
Gradle —— 写一个 Task

Gradle —— 写一个 Task

作者: 你可记得叫安可 | 来源:发表于2019-11-30 18:10 被阅读0次

以下代码使用 Gradle 5.4.1

1. 概念

Gradle 提供了一个构建任意类型项目的框架,如果你需要构建某个具体的项目,比如 Spring 或者 Android,那么就需要提供管理这种项目类型的 PluginAndroid 就是 Android Gradle Plugin(AGP)AGP 需要和特性版本的 Gradle 配合使用:Android Gradle 插件版本说明。这些 Plugin 中有许多 Task,它们共同为项目构建提供了生命周期的管理。

2. PluginTask

2.1 一个简单的 Task

ProjectTask 的创建和执行提供了上下文,所有的 Plugin 要么向 Project 中添加用于配置的 Property,要么向 Project 中添加不同的 Task。一个 Task 表示一个逻辑上较为独立的执行过程,比如编译 Java 源码,拷贝文件等。来看一个 Hello world Task:

// 通过 gradle init 来生成 build.gradle
tasks.register("hello") {
    doLast {
        println 'Hello, World!'
    }
}

上面的代码往 Gradletasks 中注册了一个新的名叫 helloTask,并且这个 Task 有个 Action,它打印 Hello, World! 到控制台。
如果执行命令:gradle tasks --all,那么就会看到所有的 Task

Tasks
我们可以看到,Gradle 其实已经内置了一些基本的 Task,这些基本的 Task 与我们的 hello 相比,多了许多说明。我们可以通过往脚本中加入以下语句达到相同效果:
tasks.register("hello") {
    group = 'Welcome'
    description = 'Produces a greeting'

    doLast {
        println 'Hello, World!'
    }
}
2.2 一个自定义 Task
class Greeting extends DefaultTask {
    String message
    String recipient

    @TaskAction
    void sayGreeting() {
        println "${message}, ${recipient}!"
    }
}

tasks.register("hello", Greeting) {
    group = 'Welcome'
    description = 'Produces a greeting'
    message = 'Hello'
    recipient = 'World'
}

通过继承 DefaultTask 来自定义 Greeting Task。它跟 2.1 中示例一样,提供两个配置项:groupdescription。通过注解 @TaskAction 来实现 Greetingaction

2.1 中的写法就像是一个匿名内部类,而 2.2 的写法则更像是声明一个具体类 Greeting,并实例化一个 hello 的实例。

因为 Greeting 是一个 Task 的类声明,所以我们可以再写一个德语版本的实例:

tasks.register("gutenTag", Greeting) {
    group = 'Welcome'
    description = 'Produces a German greeting'
    message = 'Guten Tag'
    recipient = 'Welt'
}
2.3 另一种写法

关于 Task 的实例化,我们还有另外一种更 groovy style 的写法:

task helloWorld(type: Greeting) {
    group = 'Welcome'
    description = 'other writing style'
    message = 'Hello'
    recipient = 'world'
}

那么 2.3 中的写法与之前的写法有什么不同呢?

  • 其实,每个 Project 中都有一个 TaskContainerProject 的实例维护了一个 TaskContainer 类型的属性 tasks。我们通过查 TaskContainer API 可以知道,当我们写 tasks.register() 来创建一个 Task 实例时,其实是调用的 TaskContainer.register()
  • 2.3 的写法中,task 其实是 build.gradle 文件的关键字。how-to-translate-task-keyword-in-dsl-into-groovy-call,通过 Compile-time metaprogramming and AST transformations,最后将其转换为调用 Project#task(Map<String, ?> args, String name, Closure configureClosure)。这其中还涉及到 groovy 的一个属性:它会收集方法调用中所有有名参数,将这些参数转换成一个 Map,再去调用这个方法的第一个参数为 Map 的重载方法。因此 task 关键字如果带参数的话,最后将会被转换并调用 Project#task(Map<String, ?> args, String name, Closure configureClosure)

3. 内建 Task

我们还可以继承一个内建 Task,比如 Copy

task copyFile(type: Copy) {
    from 'srcFile'
    into 'destFile'
}

以上 copyFilesrcFile 文件夹中的内容拷贝到 destFile 文件夹中。这里的两个文件夹都是相对于当前 Project 而言的,即 build.gradle 文件所在的目录。


Task 之间可以存在依赖关系,比如 taskA 依赖于 taskB,那么在执行 taskA 时,Gradle 会先执行 taskB,然后再执行 taskA。声明 Task 依赖关系的一种方式是在定义一个 Task 的时候:

task taskA(dependsOn: taskB) {
   //do something
}

task copyFile(type: Copy, dependsOn: hello) {
    from 'srcFile'
    into 'destFile'
}

那么上面重新定义的 copyFile 在执行前,Gradle 会先执行 hello

3. Task 的生命周期概览

上面提到的 description 我们还可以在闭包中设置它。

task hello8 {
    doLast {
        println description
    }
}

hello8 {
    description = "this is hello8"
}

上面代码虽然将 description 的配置放在了最后,但是执行 gradle hello8 仍然可以看到 this is hello8 被正确打印。这是因为,Gradle 在执行 Task 时分为两个阶段,首先是配置阶段,然后才是实际执行阶段。所以在执行 hello8 之前,Gradle 会扫描整个 build.gradle 文件,将 hello8description 设置为 this is hello8,然后执行 hello8

相关文章

网友评论

      本文标题:Gradle —— 写一个 Task

      本文链接:https://www.haomeiwen.com/subject/opwowctx.html