美文网首页
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