• Gradle系列【5】任务Task


    有道无术,术尚可求,有术无道,止于术。

    前言

    在Gradle 中,任务是最小执行单元,一个build.gradle是由一系列的任务组成。每个项目都由不同的任务组成。任务是构建执行的一项工作。任务可以是编译一些类,将类文件存储到单独的目标文件夹中,创建JAR,生成Javadoc或将一些归档发布到存储库。

    创建任务

    task是用于将任务定义到构建脚本中的关键字。

    比如我们定义一个任务,然后在工具栏中就可以执行,和Maven 中的目标一样,就是一个功能。
    在这里插入图片描述
    一些常见创建任务的方式如下所示:

    // 1. 定义一个任务
    task hello {
        println 'hello world'
    }
    // 2. 使用参数定义任务名
    task('task001') {
        println "task001"
    }
    // 3. 使用tasks 集合对象创建任务
    tasks.create("task002") {
        println "task002"
    }
    // 4. 使用project获取tasks 集合对象创建任务
    project.getTasks().create("task003") {
        println "task003"
    }
    // 5. 向tasks 集合中注册任务,被使用时才会创建
    tasks.register('task004') {
        println 'task004'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    还可以在添加任务的时候对其进行分组,比如:

    task taskDev1{
        // 分组到dev
        group "dev"
        description "项目描述"
        println "method1"
    }
    task('taskDev2'){
        // 分组到dev
        group "dev"
        println "method2"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    分组后,在工具栏任务列表就可以看到:
    在这里插入图片描述

    任务管理

    创建的任务都放在了TaskContainer 对象统一管理。
    在这里插入图片描述
    TaskContainer 常用定位任务方法如下所示:

    // 1. 根据任务名查询任务,没有抛出NULL
    println tasks.findByPath('task004').path
    println tasks.findByPath('task005').path
    // 2. 根据任务名查询任务,没有抛出UnknownTaskException
    println tasks.getByPath('task004').path
    println tasks.getByPath(':task005').path
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Action

    一个任务包含若干Action,Gradle提供了doLast()doFirst()函数,用于在执行任务时最新执行和最后执行的Action

    实例如下:

    task taskFirstLast{
        println "taskFirstLast"
        doLast{
            println "last"
        }
        doFirst{
            println "first"
        }
        group "dev"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    也可以使用如下方式编写:

    task taskFirstLast {
        println "taskFirstLast"
    }
    myTask.doFirst {
        println "first"
    }
    myTask.doLast {
        println "last"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    任务参数

    定义Task的时候是可以指定很多参数的,如下所示:

    参数含义默认值
    nametask的名字不能为空,必须指定
    typetask的“父类”DefaultTask
    overwrite是否替换已经存在的taskfalse
    dependsOntask依赖的task的集合 []
    grouptask属于哪个组null
    descriptiontask的描述null

    可以通过以下两种方式定义有参数的任务:

    task task001{
    }
    task task002{
    }
    // 1. 定义有参任务方式1
    project.task('task006', group: "dev", description: "有参任务", dependsOn: ["task001", "task002"] ) {
        println "task006"
    }
    // 2. 定义有参任务方式2
    task task007 {
        group "dev"
        description "有参任务"
        dependsOn task001, task002
        doLast {
            println "task007"
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    指定Type

    创建任务的时候可以通过type: SomeType 指定Type,Type其实就是告诉Gradle,这个新建的Task对象会从哪个基类Task派生。

    Gradle本身提供了一些通用的Task,最常见的有Copy 任务,还提供了其他如DeleteSync等。

    下面示例中是一个简单的Copy 任务:

    // 创建任务,派生自Copy, 可以实现复制文件
    task copyDocs(type: Copy) {
        from 'src/main/doc' // 被复制的文件
        into 'build/target/doc' // 目标
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Copy 的时候还可以进行重命名:

    task chVer(type: Copy) {
        from "src/main/manifest/AndroidManifestCopy.xml"  // 复制src/main/manifest/目录下的AndroidManifest.xml
        into 'src/main'  // 复制到指定目标目录
        rename { String fileName -> //在复制时重命名文件
            fileName = "AndroidManifest.xml" // 重命名
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Copy 还可以配置复制规则闭包、过滤、重命名等:

    // 这是个Ant filter
    import org.apache.tools.ant.filters.ReplaceTokens
    // 创建一个复制规则闭包
    def copyRule = copySpec {
        from 'src/data'
        include '*.data'
    }
    task initConfig(type: Copy) {
        from('src/main/config') {
            include '**/*.properties'
            include '**/*.xml'
            filter(ReplaceTokens, tokens: [version: '2.3.1']) // 过滤
        }
        from('src/main/config') {
            exclude '**/*.properties', '**/*.xml'
        }
        from('src/main/languages') {
            rename 'EN_US_(.*)', '$1' // 重命名
        }
        into 'build/target/config'
        exclude '**/*.bak' // 排查文件
        includeEmptyDirs = false // 是否包含空文件夹
        with copyRule // 引用规则
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    其他的一些任务类型如下所示:

    任务描述
    Copy将文件复制到目标目录
    Delete删除文件和目录
    Exec执行命令行程序
    GradleBuild执行Gradle构建
    JavaExec在一个子进程中执行一个Java程序
    Sync同步源文件文件或者目录
    Upload将源文件配置的组件上传到执行的仓库

    还可以通过继承DefaultTask类自定义类型,如下所示:

    class TestTask extends DefaultTask {
         // 定义输入参数,任务没有传入或者设置参数,将使用默认参数
        @Input
        String message = 'TestTask'
        // 定义执行方法
        @TaskAction
        def hello(){
            println "Hello:$message"
        }
    }
    // 注册任务,没有传入参数
    tasks.register('myTask', TestTask)
    
    // 注册任务,并定义参数值
    task hi(type:TestTask){
        message ="Hi"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    任务依赖

    任务之间也具有依赖性,通过dependsOn 指定任务名称,就表示依赖其他任务。

    同一个工程中建立依赖关系如下所示,执行时,会先执行依赖中的任务,在执行当前任务。

    task depends001 {
         println 'depends001'
    }
    task depends002 {
        dependsOn depends001
        println 'depends002'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果依赖其他项目的任务,按照如下写法:

    project('project-a') {
        task taskX {
            dependsOn ':project-b:taskY' // 依赖其他项目的任务
            doLast { println 'taskX' }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行顺序

    任务是可以进行排序的,通过这种方式可以在某些情况下控制任务的执行顺序,而不是通过强制依赖的方式。这个功能是非常有用的,比如项目中设置的顺序是必须先执行单元测试,然后才能进行集成测试来保证软件的质量,测速完成后再打包上传发布等操作。

    Gradle中有两种排序方式:

    • mustRunAfter:必须在某个任务之后执行
    • shouldRunAfter :应该在某个任务之后执行

    如下所示,不过好像执行必须写在doFirst或者doLast中才有效。

    task order001 {
        doFirst{
            println "<< order001 doFirst 的打印"
        }
    }
    task order002 {
        doFirst{
            println "<< order002 doFirst 的打印"
        }
    }
    order001.mustRunAfter order002
    //order001.shouldRunAfter order002
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    条件执行

    可以给任务加上条件判断决定是否执行该任务,onlyIf 表达式为真时,任务才会执行。

    task test009 {
        doLast { println '=======test009' }
    }
    // onlyIf 中的表达式为真,才执行任务
    test009.onlyIf { !project.hasProperty('avab') }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以直接设置是否开启任务:

    // 是否开启任务,false 表示不开启任务
    test009.enabled = false
    
    • 1
    • 2

    还可以抛出StopExecutionException异常,如果遇到这个异常,那么该任务将不会被执行:

    task test010 {
        doLast { println 'test010' }
    }
    test010.doFirst {
        // 条件判断,抛出异常,该任务后续则不执行
        throw new StopExecutionException()
    }
    task test011 {
        dependsOn('test010')
        doLast {
            println 'test011'
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    定义规则

    tasks.addRule可以定义一些规则:

    当执行、依赖一个不存在的任务时,Gradle 会执行失败,提示信息是任务不存在。可以使用规则对其进行修改,让其在执行、依赖不存在的任务时,不会执行失败,而是打印提示信息。代码如下所示:

    tasks.addRule("对该规则的一个,便于调试等"){ String taskName ->
        task(taskName){
            doLast{
                println "该 ${taskName} 任务不存在,请查证后再执行"
            }
        }
    }
    task taskRule{
        dependsOn missTask
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    最终任务

    和java中的finally一样,task也可以指定对应的最终必须执行的任务,即使上面的任务中抛出了异常。

    task taskX { 
        doLast { 
            println 'taskX' 
        } 
    } 
    task taskY { 
        doLast { println 'taskY' } 
    } 
    taskX.finalizedBy taskY 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    vue3中使用viewerjs实现图片预览效果
    XML学习总结
    动态爬虫管理平台构建与实现_kaic
    商务呈现-售前评估&支持
    网工知识角|什么是防火墙你知道吗?一篇直接搞懂
    STM32 Debug查看const变量 在flash中存储地址
    【哈希表】算法例题
    多维时序 | MATLAB实现WOA-CNN-BiLSTM-Attention多变量时间序列预测(SE注意力机制)
    python GUI编程 PyQT5
    ES中的三种查询
  • 原文地址:https://blog.csdn.net/qq_43437874/article/details/125381777