天天看點

Android Gradle 自定義Task 詳解

轉載請标明出處:http://blog.csdn.net/zhaoyanjun6/article/details/76408024

本文出自【趙彥軍的部落格】

一:Gradle 是什麼

  • Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化建構工具。
  • 它使用一種基于Groovy的特定領域語言(DSL)來聲明項目設定,抛棄了基于XML的各種繁瑣配置。面向Java應用為主。
  • 目前其支援的語言限于Java、Groovy、Kotlin和Scala,計劃未來将支援更多的語言。基于 groovy 腳本建構,其 build 腳本使用 groovy 語言編寫。

關于 gradle 相關運用,可以移步 :Android Gradle使用總結

二:groovy 是什麼

Groovy是一種動态語言,它和Java類似(算是Java的更新版,但是又具備腳本語言的特點),都在Java虛拟機中運作。當運作Groovy腳本時它會先被編譯成Java類位元組碼,然後通過JVM虛拟機執行這個Java位元組碼類。

關于 groovy 相關知識,移步到這裡:Groovy 使用完全解析

三:Gradle 的 Project 和 Tasks

每次建構(build)至少由一個project構成,一個project 由一到多個task構成。每個task代表了建構過程當中的一個原子性操作,比如編譯,打包,生成javadoc,釋出等等這些操作。

gradle : 一個 project 包含多個 task,一個 task 包含多個 Action

project 
                  -- task1 (Action1、Action2...)
                  -- task2 (Action1、Action2...)
                  -- ... 
           

四:自定義 Task

  • 格式:
task 任務的名字 {
    //do some things
 }

           
  • 例子

build.gradle

//定義 task , 名字 hello 
task hello{
    println "hello world"
}

//定義 task,名字 hello 
task(hello2){
    println "hello world2"
}

//定義 task,名字 hello3 
task ('hello3'){
    println "hello world3"
}


           
  • 在終端運作 gradle 指令
//執行 hello task
gradlew hello

//執行 hello2 task
gradlew hello2

//執行 hello3 task
gradlew hello3

           

五:建立Action

在上面的舉例中,是一個非正式的 task , 說非正式是因為建立的 task 裡面沒有 action 。task 本質上又是由一組被順序執行的 Action 對象構成,Action其實是一段代碼塊,類似于Java中的方法。

建立 Action 相關 API

//在Action 隊列頭部添加Action
 Task doFirst(Action<? super Task> action);
 Task doFirst(Closure action);

 //在Action 隊列尾部添加Action
 Task doLast(Action<? super Task> action);
 Task doLast(Closure action);
    
 //已經過時了,建議用 doLast 代替
 Task leftShift(Closure action);

 //删除所有的Action
 Task deleteAllActions();

           

小例子

//建立一個名字為hello的 task 
task hello {

    //建立一個 Action , 添加到 Action 清單的頭部
   doFirst(new Action<Task>() {
       @Override
       void execute(Task task) {
           println "action1++++++++++"
       }
   })

    //建立一個 Action , 添加到 Action 清單的頭部
    doFirst {
        println "action2++++++++++"
    }

}

           

在 Action 清單中添加了 兩個 Action , Action 清單如下圖所示:

運作 hello task :

gradle hello

運作結果:

action2++++++++++
action1++++++++++

           

leftShift 說明

leftShift 的作用和 doLast 一樣,在action 清單尾部添加一個Action,隻不過現在過時了,官方建議用 doLast 代替。下面舉個小例子:

task hello {
    //在 Action 清單尾部添加一個 Action 
    leftShift {
        println "+++++"
    }
}

           

leftShift 還有一種簡潔寫法,用

<<

代替, 如下所示:

task hello <<{
    //在 Action 清單尾部添加一個 Action 
    println "+++++"
}

           

那麼問題來了,task 中的 Action 在什麼時候執行?

六:Gradle 生命周期

1.初始化階段

會去讀取根工程中 setting.gradle 中的 include 資訊,決定有哪幾個工程加入建構,建立 project 執行個體,比如下面有三個工程: include ':app', ':lib1', ':lib2 。

2.配置階段

會去執行所有工程的 build.gradle 腳本,配置 project對象,一個對象由多個任務組成,

此階段也會去建立、配置task及相關資訊。

3.運作階段

根據gradle指令傳遞過來的task名稱,執行相關依賴任務。Task 的 Action 會在這個階段執行。

七:建立 Task 的另外一種方式

在上面講解了建立 task 的基本方式,其實 gradle api 給我們提供了其他的方式建立 task ,下面講解其他兩種方式。

  • tasks
//建立 hello2 task
tasks.create("hello2"){
    doFirst {
        println "hello2+++++"
    }
}
           
  • 自定義 DefaultTask 子類
class MyTask extends DefaultTask {
    
    @TaskAction
    void action(){
        println "action1+++++"
    }
}

//建立 hello3 task
task hello3 (type: MyTask){
    doLast{
       println "action2+++++"
    }
}

           

運作 hello3 task:

gradlew hello3

輸出

action1+++++

action2+++++

八: Task 依賴

1、dependsOn

task task1 << {
    println "我是task1----"
}

task task2 << {
    println "我是task2----"
}

//task2 依賴 task1, 執行task2之前先執行task1
task2.dependsOn task1

           

執行 task2

gradlew task2

執行效果

我是task1----

我是task2----

2、mustRunAfter

兩個 task 依賴

task task1 << {
    println "我是task1----"
}

task task2 << {
    println "我是task2----"
}

//task2 運作之前先運作task1
task2.mustRunAfter task1

           
  • 執行 task1 : gradlew task1
  • 執行 task2 : gradlew task2
  • 同時執行 task1、task2 : gradlew task1 task2

三個 task 互相依賴

task task1 << {
    println "我是task1----"
}

task task2 << {
    println "我是task2----"
}

task task3 << {
    println "我是task3----"
}

task2.mustRunAfter task1
task3.mustRunAfter task1

           
  • 執行 gradlew task1 task2 task3
我是task3----
  • 執行 gradlew task1 task3 task2

在出現文法沖突的情況下,依賴關系形成閉環,編譯器會報錯

task1.mustRunAfter task2
task2.mustRunAfter task1
           

3、shouldRunAfter

形成依賴關系可有可無。

task task1 << {
    println "我是task1----"
}

task task2 << {
    println "我是task2----"
}

task1.shouldRunAfter task2

           

運作:

gradlew task1 task2

在出現文法沖突的情況下,依賴關系形成閉環,會自動打破閉環。不會報錯

九:系統預設 task

gradle 預設提供了很多 task 給我們使用,比如 copy、delete

1、copy

task 任務的名字 (type: Copy) {
    //action 
}

           
  • Api 介紹
//資料源目錄,多個目錄
public AbstractCopyTask from(Object... sourcePaths)  

//目标目錄,單一
public AbstractCopyTask into(Object destDir) 

//過濾檔案 包含
public AbstractCopyTask include(String... includes)

//過濾檔案 排除
public AbstractCopyTask exclude(String... excludes)

//重新命名,老名字 新名字
public AbstractCopyTask rename(String sourceRegEx, String replaceWith)

//删除檔案 Project 接口
boolean delete(Object... paths);

           

小例子:

  • 複制圖檔:單一資料源
task copyImage(type: Copy) {
    from 'C:\\Users\\yiba_zyj\\Desktop\\gradle\\copy'
    into 'C:\\Users\\yiba_zyj\\Desktop'
}

           
  • 複制圖檔:多個資料源
task copyImage(type: Copy) {
    from 'C:\\Users\\yiba_zyj\\Desktop\\gradle\\copy' , 
         'C:\\Users\\yiba_zyj\\Desktop\\gradle\\copy'
    
    into 'C:\\Users\\yiba_zyj\\Desktop'
}

           
  • 複制圖檔:過濾檔案

隻會複制字尾為 .jpg 的檔案

task copyImage(type: Copy) {
    from 'C:\\Users\\yiba_zyj\\Desktop\\gradle\\copy'
    into 'C:\\Users\\yiba_zyj\\Desktop'
    include "*.jpg" 
}

           
  • 複制檔案:過濾檔案,重命名
task copyImage(type: Copy) {
    from 'C:\\Users\\yiba_zyj\\Desktop\\gradle\\copy'
    into 'C:\\Users\\yiba_zyj\\Desktop'
    include "*.jpg"
    exclude "image1.jpg"
    rename("image2.jpg","123.jpg")
}

           

檔案覆寫規則

相同檔案覆寫

Copy 類的繼承圖

Copy (類)
   - AbstractCopyTask (抽象類)  (from、 into、 include、rename)
      -ConventionTask(抽象類)
       - DefaultTask (類)
        - AbstractTask (抽象類)
           - TaskInternal (接口)
            - Task(接口)        
              -Comparable<Task>, ExtensionAware(接口)
                -Project(接口)    (delete 方法)

           

2、Delete

  • 删除 Android 更目錄的aaa 檔案
task deleteFile(type: Delete) {
    //删除Android 更目錄的aaa 檔案
    delete '../aaa'  
}

           
  • 删除桌面上的檔案
task deleteFile(type: Delete) {
    //删除系統桌面 delete 
    delete "C:\\Users\\yiba_zyj\\Desktop\\gradle\\delete"
}

           

十:小技巧

1、自定義 task 的名字用駝峰命名法

task deleteFile{
    //do some things
}

           

運作

gradlew dF 等價 gradlew deleteFile

打包時候運作

gradlew assembleRelease

,可以簡寫成

gradlew aR

2、常見的 gradlew 指令

檢視項目所有預設自帶的 task,不包括自定義 task

gradlew tasks

檢視所有 task (預設 task + 自定義task)

gradlew tasks --all

檢視某個 task 的相關資訊,這些結果包含了任務的路徑、類型以及描述資訊等

gradlew help --task taskName

檢視 gradle 版本

gradlew -version

3、給task 添加描述 description

task task1 << {
    description = "這是一段描述資訊"
    println "我是task1----"
}

           

十一:Gradle 環境變量配置

在上面的介紹中,運作 task 的方式是用

gradlew

, 那我們怎麼用

gradle

。如果在終端運作

gradle

就會提示

gradle 不是内部或外部指令,也不是可運作的程式或批處理檔案。

'gradle' 不是内部或外部指令,也不是可運作的程式或批處理檔案。

           

官網下載下傳:http://services.gradle.org/distributions/

下載下傳完成後,我将壓縮包解壓放在 d 盤的 soft 目錄中。

環境變量

  • GRADLE_HOME
D:\soft\gradle-4.3-all
  • Path
D:\soft\gradle-4.3-all\gradle-4.3\bin

參考資料

1、Android Gradle 必備實用技巧

2、Android Gradle使用總結

3、Groovy 使用完全解析

4、深入了解 Android Gradle 詳解

個人微信号:zhaoyanjun125 , 歡迎關注