1. 程式人生 > >Gradle技術之四 - Gradle的Task詳解

Gradle技術之四 - Gradle的Task詳解

1 Gradle的Task詳解

  • 1 Task定義和配置
  • 2 Task的執行
  • 3 Task的依賴和執行順序
  • 4 Task型別
  • 5 Task結合gradle的生命週期
  • 6 Task實戰

1.1 Task定義和配置

1.1.1 檢視所有的task

./gradlew tasks
輸出
> Task :tasks 

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.

Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.

.....

1.1.1 新建一個task

可以使用project的task()方法建立一個task,也可以使用project的TaskContainer去建立task,這兩種方法建立的task沒有任何區別,TaskContainer就是方便project管理task用的,通過TaskContainer可以對project下的task進行管理,比如建立,查詢task等


//第一種方法,直接使用project的task()方法建立
task helloTask{
    println 'this is helloTask'
}


//第二種方法,使用TaskContainer建立task
this.tasks.create(name:'helloTask2'){
    println 'this is helloTask2'
}

1.1.2 對task進行配置

有兩種方法可以對task進行配置
1 建立的時候就對task進行配置
2 在閉包中對task進行配置

//第一種方法,直接使用project的task()方法建立
//第一種配置方法,建立的時候就配置task的group和description
//description就是個說明,類似對註釋
task helloTask(group:'hard',description:'task learn'){
    println 'this is helloTask'
}


//第二種方法,使用TaskContainer建立task
this.tasks.create(name:'helloTask2'){
    //第二種配置方式:直接在閉包中配置
    setGroup('hard')
    setDescription('task learn')
    println 'this is helloTask2'
}

通過配置以後,就可以在右側的面板中看到task了,如下圖:

1.1.3 task的執行順序

//第一種方法,直接使用project的task()方法建立
//配置的時候就配置task的group和description
//description就是個說明,類似對註釋
task helloTask(group:'hard',description:'task learn'){

    //直接寫在閉包裡面的,是在配置階段就執行的
    println 'this is helloTask'

    doFirst {
        println 'task in do first'  //執行任務時,會第一個執行
    }

    doLast {
        println 'task in do last'   //執行任務時,會最後一個執行
    }
}

doFirst和doLast中的程式碼,不執行這個任務時,是不會執行的,但是直接寫在閉包中的,就也是在這兩個函式外的程式碼,是在配置階段就會執行的。執行任務時,doFirst中的程式碼最先執行,doLast中的程式碼最後執行

切記大部分的內容是寫在 doLast{} 或 doFirst{} 閉包中,因為寫在如果寫在 task 閉包中的話,會在 Configuration 階段也被執行。

1.1.4 計算build編譯時間

def startBuildTime
def endBuildTime

//配置完後,所有的task的拓撲圖都已經生成好了
//保證要找的task已經配置完畢
this.afterEvaluate { Project project ->
    
    //找到第一個執行的task
    def preBuildTask = project.tasks.getByName('preBuild')
    preBuildTask.doFirst {
        startBuildTime = System.currentTimeMillis()
        println 'the start time is:' + startBuildTime
    }

    //找到最後一個編譯的build任務
    def buildTask = project.tasks.getByName('build')
    buildTask.doLast {
        endBuildTime = System.currentTimeMillis()
        println 'the build time is:' + (endBuildTime - startBuildTime)
    }
}

1.1.5 task依賴
task之間是有依賴關係的,比如taskA 依賴 taskB,那麼在執行taskA的時候,Gradle會先執行taskB,再執行taskA,我們可以在定義一個task的時候,指定task的依賴關係:

task taskB {
    doLast {
        println '我是taskB'
    }
}

//定義一個taskA,且依賴於taskB
task taskA(dependsOn: taskB) {
    doLast {
        println '我是taskA'
    }
}

//執行
./gradlew taskA

輸出
> Task :app:taskB 
我是taskB

> Task :app:taskA 
我是taskA

或者定義taskA,taskB之後,再定義依賴關係:

task taskB {
    doLast {
        println '我是taskB'
    }
}

//定義一個taskA
task taskA() {
    doLast {
        println '我是taskA'
    }
}

//定義之後,再依賴於taskB
taskA.dependsOn taskB

//執行
./gradlew taskA

輸出
> Task :app:taskB 
我是taskB

> Task :app:taskA 
我是taskA

一個task也可以依賴多個task,依賴多個task的話,直接在denpendsOn後面跟一個task列表:

taskA.dependsOn 'taskB','taskC'
或者在定義的時候
task taskA(dependsOn:['taskB','taskC']) {
    doLast {
        println '我是taskA'
    }
}

執行taskA的時候,先執行taskB,taskC,但是taskB,taskC的執行順序是隨機的。

1.1.6 將自定義的task掛到構建過程中去
比如有這樣一個需求,我們需要在build之後,就執行我們的task,應該怎麼寫呢?
這就是把我們自定義的task掛到build後,程式碼如下:

afterEvaluate{ project ->
    def buildTask = project.tasks.findByName('build')
    if(buildTask == null){
        throw new GradleException('the build task is not found')
    }

    //在buildTask後新增doLast,並在裡面執行printTask
    //這樣我們就把自定義的task掛到build構建過程中了
    buildTask.doLast {
        printTask.execute()
    }
}

SourceSets類的作用

SourceSets類的作用就是定義去哪找原始檔,去哪找資原始檔,庫檔案等,那麼為什麼我們平時不用定義也會知道去哪找這些東西呢?那是因為gradle有個約定的配置,如果沒有指定,就會使用約定的。所以我們修改這些位置。如下:

  sourceSets {
        main {
            jniLibs.srcDirs = ['libs'] //修改so庫存放的位置
        }
    }

    sourceSets {
        main {
            //修改資原始檔的位置
            // res存放公共的資源,res-ad 存放廣告資源,res-player存放播放器資源
            res.srcDirs = ['src/main/res', 'src/main/res-ad', 'src/main/res-player']
        }
    }