《Gradle 權威指南》讀書筆記——第四章 Gradle 任務

多種方式創建Gradle任務
在Gradle中我們可以有多種方式在創建任務

//1.直接以一個任務的名字創建任務

    def Task myTask1=task(myTask1Do)
    myTask1Do.doLast{
        println "myTask1Do.doLast"
    }

//2.以一個任務的名字+一個對該任務的配置map來創建task實例

    def Task myTask2=task(myTask2Do,group:BasePlugin.BUILD_GROUP)
    myTask2Do.doLast{
        println "myTask2Do=$myTask2Do.group"
    }

//3.閉包方式

    task myTask3Do{
        //閉包中的委託對象是task,description是task的屬性
        description '描述'
        doLast{
            println "myTask3Do:$description"
        }
    }

多種方式訪問task

//1.task在創建時,會作爲project的屬性添加到project上,所以我們可以通過任務名字來定義和使用task
task mytask
//[]在Groovy是操作符,是getAt()的重載
tasks["mytask"].doLast{
    println"mytask"
}

​
//2.通過路徑訪問
task.findByPath(":多方式訪問Task:mytask").doLast{
    println "mytask.findByPath" //找不到返回null
}
task.getByPath(":多方式訪問Task:mytask").doLast{
    println "mytask.findByPath" //找不到拋出UnKnownTaskException
}
//當我們拿到task的引用的時候,就可以按照我們的業務邏輯去操縱它,比如配置任務依賴,配置一些屬性

任務的分組和描述
任務的分組其實就是對任務的分類,便於我們對任務進行歸類整理;
任務的描述其實就是說明這個任務有什麼用;

//建議在創建任務的時候對這兩個屬性都要配置
task myTask{
    description "description的demo"
    group=BasePlugin.BUILD_GROUP
    doLast{
        println"description:$description,group=$group"
    }
}

當我們使用gradle tasks查看任務的時候就可以發現該任務被分類到BuildTasks中去了
使用IDE似乎鼠標懸停到任務上也可以看到描述

操作符的重載
我們都知道<< 和doLast的效果是相同的,但是爲什麼呢?
task <<

//那麼爲什麼left.shift的效果和doLast相同呢?
//源碼:
public Task doLast(final Closure action){
    hasCustomActions=true;
    if(action==null)
        throw new InvalidUserDataException("Action must not be null")
    taskMutator.mutate("Task.doLast(Closure)",new Runnable(){
        public void run(){
            action.add(convertClosureToAction(action))
        }
    })  
}
public Task leftShift(final Closure action){
    hasCustomActions=true;
    if(action==null)
        throw new InvalidUserDataException("Action must not be null")
    taskMutator.mutate("Task.leftShift(Closure)",new Runnable(){
        public void run(){
            action.add(convertClosureToAction(action))
        }
    })  
}
//可以發現這兩個方法的關鍵都是actions.add(),所以他們的效果其實都是一樣的

任務的執行分析
指定Task其實就是遍歷執行actions List
@TaskAction標齊的方法會被作爲action,然後通過task的prependParallelSafeAction被放到actionList中

Task mytask= task mytask1(type:CustomTask)
mytask.doFirst{
    println"doFirst"
}
mytask.doLast{
    println"doLast"
}
​
class CustomTask extends DefaultTask{
//TaskAction註解表明是主體方法,只能在類中的定義主體方法
    @TaskAction
    def doSelf(){
        println "doSelf"
    }
}

結果
Task執行之前執行doFirst
Task本身執行doSelf
Task執行之後執行doLast

任務的排序
通過task.shouldRunAfter
task.mustRunAfter來控制任務的執行順序

task mytask1 <<{
    println "mytask1"
}
task mytask2 <<{
    println "mytask2"
}
//依賴的順序不當的話
//Circular dependency between the following tasks:
​
//強制要求
mytask1.mustRunAfter mytask2
//非強制要求,不一定會按照該順序執行
mytask2.shouldRunAfter mytask1

任務的禁用和啓用
task中有一個enable屬性,默認true,爲false時,執行該方法會提示該任務被跳過

task mytask {
    println"mytask"
}
mytask.enabled=false //SKIPPED

onlyIf斷言
Task.onlyIf(Closure),該閉包返回false則跳過

final String ALL="all"
final String MAIN="main"
final String OTHERS='other'
​
project.ext{
    build_apps=ALL
}
​
task yingyongbao {
    println "打應用寶的包"
}
yingyongbao.onlyIf{
    def flag=true
    if(project.hasProperty("build_apps")){
        Object buildType=project.property("build_apps")
        if(ALL.equals(buildType)||MAIN.equals(buildType)){
            flag=true
        }else{
            flag=false
        }
    }
    flag
}
​
task huawei << {
    println "打華爲的包"
}
huawei.onlyIf{
    def flag=true
    if(project.hasProperty("build_apps")){
        Object buildType=project.property("build_apps")
        if(OTHERS.equals(buildType)||ALL.equals(buildType)){
            flag=true
        }else{
            flag=false
        }
    }
    flag
}
​
task sixty <<{
    println "打360的包"
}
sixty.onlyIf{
    def flag=true
    if(project.hasProperty("build_apps")){
        Object buildType=project.property("build_apps")
        if(OTHERS.equals(buildType)||ALL.equals(buildType)){
            flag=true
        }else{
            flag=false
        }
    }
    flag
}
task build 
​
build.dependsOn yingyongbao,huawei,sixty

通過 build_apps 屬性控制我們要打哪些包
#打所有的渠道包
./gradlew  :example48:build
./gradlew  -Pbuild_apps=all :example48:build
​
#打首發包
./gradlew  -Pbuild_apps=shoufa :example48:build
​
​
#打非首發包
./gradlew  -Pbuild_apps=exclude_shoufa :example48:build
​

任務的規則
我們創建的任務都在TaskContainer中,是由其進行管理的.
TaskContainer繼承於NamedDomainObjectCollection,NamedDomainObjectCollection是唯一一個具有唯一不變名字的域的對象的集合,它裏面所有的元素都具有唯一不變的名字:String,所以我們可以通過名字獲取該元素.
添加自定義規則:一個是直接添加一個rule ,一個是通過閉包配置成一個Rule 再添加。

  /**
     * Adds a rule to this collection. The given rule is invoked when an unknown object is requested by name.
     *
     * @param rule The rule to add.
     * @return The added rule.
     */   
    Rule addRule(Rule rule);
​
    /**
     * Adds a rule to this collection. The given closure is executed when an unknown object is requested by name. The
     * requested name is passed to the closure as a parameter.
     *
     * @param description The description of the rule.
     * @param ruleAction The closure to execute to apply the rule.
     * @return The added rule.
     */
    Rule addRule(String description, Closure ruleAction);


規則的作用:
當查找不到我們要查找到的任務的時候,就會調用我們添加的規則來處理這種異常情況
源碼可知,通過addRule(String,Closure)來配置規則.
當我們執行依賴一個不存在的任務時,Gradle會執行失敗,通過編寫規則我們可以改成打印提示信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章