天天看點

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

本文作者

作者:jsonchao

連結:

https://juejin.im/post/5e9c46c8518825737f1a7b4c

本文由作者授權釋出。

吹爆系列:深入探索Android卡頓優化 吹爆系列:深入探索Android布局優化大科普 吹爆系列:深入探索 Android 包體積優化 吹爆系列:深入探索Android穩定性優化 幾乎包含了市面上所有啟動優化方案

作者jsonchao 也有自己的公衆号了,大家可以微信搜尋 jsonchao 就能找到。

另外本文很長,注意收藏~

0 前言

從明面上看,Gradle 是一款強大的建構工具,而且許多文章也僅僅都把 Gradle 當做一款工具對待。但是,Gradle 不僅僅是一款強大的建構工具,它看起來更像是一個程式設計架構。Gradle 的組成可以細分為如下三個方面:

  • 1)、groovy 核心文法:包括 groovy 基本文法、閉包、資料結構、面向對象等等。
  • 2)、Android DSL(build scrpit block):Android 插件在 Gradle 所特有的東西,我們可以在不同的 build scrpit block 中去做不同的事情。
  • 3)、Gradle API:包含 Project、Task、Setting 等等(本文重點)。

可以看到,Gradle 的文法是以 groovy 為基礎的,而且,它還有自己獨有的 API,是以我們可以把 Gradle 認作是一款程式設計架構,利用 Gradle 我們可以在程式設計中去實作項目建構過程中的所有需求。

需要注意的是,想要随心所欲地使用 Gradle,我們必須提前掌握好 groovy,如果對 groovy 還不是很熟悉的建議看看 《深入探索Gradle自動化建構技術(二、Groovy 築基篇)》 一文。

https://juejin.im/post/5e97ac34f265da47aa3f6dca

需要注意的是,Groovy 是一門語言,而 DSL 一種特定領域的配置檔案,Gradle 是基于 Groovy 的一種架構工具,而 gradlew 則是 gradle 的一個相容包裝工具。

1 Gradle 優勢

1、更好的靈活性

在靈活性上,Gradle 相對于 Maven、Ant 等建構工具, 其 提供了一系列的 API 讓我們有能力去修改或定制項目的建構過程。例如我們可以 利用 Gradle 去動态修改生成的 APK 包名,但是如果是使用的 Maven、Ant 等工具,我們就必須等生成 APK 後,再手動去修改 APK 的名稱。

2、更細的粒度

在粒度性上,使用 Maven、Ant 等建構工具時,我們的源代碼和建構腳本是獨立的,而且我們也不知道其内部的處理是怎樣的。但是,我們的 Gradle 則不同,它 從源代碼的編譯、資源的編譯、再到生成 APK 的過程中都是一個接一個來執行的。

此外,Gradle 建構的粒度細化到了每一個 task 之中。并且它所有的 Task 源碼都是開源的,在我們掌握了這一整套打包流程後,我們就可以通過去修改它的 Task 去動态改變其執行流程。例如 Tinker 架構的實作過程中,它通過動态地修改 Gradle 的打包過程生成 APK 的同時,也生成了各種更新檔檔案。

3、更好的擴充性

在擴充性上,Gradle 支援插件機制,是以我們可以複用這些插件,就如同複用庫一樣簡單友善。

4、更強的相容性

Gradle 不僅自身功能強大,而且它還能 相容所有的 Maven、Ant 功能,也就是說,Gradle 吸取了所有建構工具的長處。

可以看到,Gradle 相比于其它建構工具,其好處不言而喻,而其 最核心的原因就是因為 Gradle 是一套程式設計架構。

2 Gradle 建構生命周期

Gradle 的建構過程分為 三部分:初始化階段、配置階段和執行階段。其建構流程如下圖所示:

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

下面分别來詳細了解下它們。

1、初始化階段

首先,在這個階段中,會讀取根工程中的 setting.gradle 中的 include 資訊,确定有多少工程加入建構,然後,會為每一個項目(build.gradle 腳本檔案)建立一個個與之對應的 Project 執行個體,最終形成一個項目的層次結構。

與初始化階段相關的腳本檔案是 settings.gradle,而一個 settings.gradle 腳本對應一個 Settings 對象,我們最常用來聲明項目的層次結構的 include 就是 Settings 對象下的一個方法,在 Gradle 初始化的時候會構造一個 Settings 執行個體對象,以執行各個 Project 的初始化配置。

settings.gradle

在 settings.gradle 檔案中,我們可以 在 Gradle 的建構過程中添加各個生命周期節點監聽,其代碼如下所示:

':app'
           

編寫完相應的 Gradle 生命周期監聽代碼之後,我們就可以在 Build 輸出界面看到如下資訊:

tasks: [clean, 
           

此外,在 settings.gradle 檔案中,我們可以指定其它 project 的位置,這樣就可以将其它外部工程中的 moudle 導入到目前的工程之中了。示例代碼如下所示:

2、配置階段

配置階段的任務是 執行各項目下的 build.gradle 腳本,完成 Project 的配置,與此同時,會構造 Task 任務依賴關系圖以便在執行階段按照依賴關系執行  Task。而在配置階段執行的代碼通常來說都會包括以下三個部分的内容,如下所示:

  • 1)、build.gralde 中的各種語句。
  • 2)、閉包。
  • 3)、Task 中的配置段語句。

需要注意的是,執行任何 Gradle 指令,在初始化階段和配置階段的代碼都會被執行。

3、執行階段

在配置階段結束後,Gradle 會根據各個任務 Task 的依賴關系來建立一個有向無環圖,我們可以通過 Gradle 對象的 getTaskGraph 方法來得到該有向無環圖 => TaskExecutionGraph,并且,當有向無環圖建構完成之後,所有 Task 執行之前,我們可以通過 whenReady(groovy.lang.Closure) 或者 addTaskExecutionGraphListener(TaskExecutionGraphListener) 來接收相應的通知,其代碼如下所示:

new
           

然後,Gradle 建構系統會通過調用 gradle 來執行相應的各個任務。

4、Hook Gradle 各個生命周期節點

這裡借用 Goe_H 的 Gradle 生命周期時序圖來講解一下 Gradle 生命周期的整個流程,如下圖所示:

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

可以看到,整個 Gradle 生命周期的流程包含如下 四個部分:

  • 1)、首先,解析 settings.gradle 來擷取子產品資訊,這是初始化階段。
  • 2)、然後,配置每個子產品,配置的時候并不會執行 task。
  • 3)、接着,配置完了以後,有一個重要的回調 project.afterEvaluate,它表示所有的子產品都已經配置完了,可以準備執行 task 了。
  • 4)、最後,執行指定的 task 及其依賴的 task。

在 Gradle 建構指令中,最為複雜的指令可以說是 gradle build 這個指令了,因為項目的建構過程中需要依賴很多其它的 task。這裡,我們以 Java 項目的建構過程看看它所依賴的 tasks 及其組成的有向無環圖,如下所示:

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

注意事項

  • 1)、每一個 Hook 點對應的監聽器一定要在回調的生命周期之前添加。
  • 2)、如果注冊了多個 project.afterEvaluate 回調,那麼執行順序将與注冊順序保持一緻。

5、擷取建構各個階段、任務的耗時情況

了解了 Gradle 生命周期中的各個 Hook 方法之後,我們就可以 利用它們來擷取項目建構各個階段、任務的耗時情況,在 settings.gradle 中加入如下代碼即可:

在 Gradle 中,執行每一種類型的配置腳本就會建立與之對應的執行個體,而在 Gradle 中如 三種類型的配置腳本,如下所示:

  • 1)、Build Scrpit:對應一個 Project 執行個體,即每個 build.gradle 都會轉換成一個 Project 執行個體。
  • 2)、Init Scrpit:對應一個 Gradle 執行個體,它在建構初始化時建立,整個建構執行過程中以單例形式存在。
  • 3)、Settings Scrpit:對應一個 Settings 執行個體,即每個 settings.gradle 都會轉換成一個 Settings 執行個體。

可以看到,一個 Gradle 建構流程中會由一至多個 project 執行個體構成,而每一個 project 執行個體又是由一至多個 task 構成。下面,我們就來認識下 Project。

3 Project

Project 是 Gradle 建構整個應用程式的入口,是以它非常重要,我們必須對其有深刻地了解。不幸的是,網上幾乎沒有關于 project 講解的比較好的文章,不過沒關系,下面,我們将會一起來深入學習 project api 這部分。

由前可知,每一個 build.gradle 都有一個與之對應的 Project 執行個體,而在 build.gradle 中,我們通常都會配置一系列的項目依賴,如下面這個依賴:

implementation 
           

類似于 implementation、api 這種依賴關鍵字,在本質上它就是一個方法調用,在上面,我們使用 implementation() 方法傳入了一個 map 參數,參數裡面有三對 key-value,完整寫法如下所示:

implementation group: 
           

當我們使用 implementation、api 依賴對應的 aar 檔案時,Gradle 會在 repository 倉庫 裡面找到與之對應的依賴檔案,你的倉庫中可能包含 jcenter、maven 等一系列倉庫,而每一個倉庫其實就是很多依賴檔案的集合伺服器, 而他們就是通過上述的 group、name、version 來進行歸類存儲的。

1、Project 核心 API 分解

在 Project 中有很多的 API,但是根據它們的 屬性和用途 我們可以将其分解為 六大部分,如下圖所示:

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

對于 Project 中各個部分的作用,我們可以先來大緻了解下,以便為 Project 的 API 體系建立一個整體的感覺能力,如下所示:

  • 1)、Project API:讓目前的 Project 擁有了操作它的父 Project 以及管理它的子 Project 的能力。
  • 2)、Task 相關 API:為目前 Project 提供了新增 Task 以及管理已有 Task 的能力。由于 task 非常重要,我們将放到第四章來進行講解。
  • 3)、Project 屬性相關的 Api:Gradle 會預先為我們提供一些 Project 屬性,而屬性相關的 api 讓我們擁有了為 Project 添加額外屬性的能力。
  • 4)、File 相關 Api:Project File 相關的 API 主要用來操作我們目前 Project 下的一些檔案處理。
  • 5)、Gradle 生命周期 API:即我們在第二章講解過的生命周期 API。
  • 6)、其它 API:添加依賴、添加配置、引入外部檔案等等零散 API 的聚合。

2、Project API

每一個 Groovy 腳本都會被編譯器編譯成 Script 位元組碼,而每一個 build.gradle 腳本都會被編譯器編譯成 Project 位元組碼,是以我們在 build.gradle 中所寫的一切邏輯都是在 Project 類内進行書寫的。

下面,我們将按照由易到難的套路來介紹 Project 的一系列重要的 API。

需要提前說明的是,預設情況下我們標明根工程的 build.gradle 這個腳本檔案中來學習 Project 的一系列用法,關于 getAllProject 的用法如下所示:

1、getAllprojects

getAllprojects 表示 擷取所有 project 的執行個體,示例代碼如下所示:

/**
 * getAllProjects 使用示例
 */
           

首先,我們使用了 def 關鍵字定義了一個 getProjects 方法。然後,在注釋1處,我們調用了 getAllprojects 方法傳回一個包含根 project 與其子 project 的 Set 集合,并鍊式調用了 eachWithIndex 周遊 Set 集合。

接着,在注釋2處,我們會判斷目前的下标 index 是否是0,如果是,則表明目前周遊的是 rootProject,則輸出 rootProject 的名字,否則,輸出 child project 的名字。

下面,我們在指令行執行 ./gradlew clean,其運作結果如下所示:

可以看到,執行了初始化之後,就會先配置我們的 rootProject,并輸出了對應的工程資訊。接着,便會執行子工程 app 的配置。最後,執行了 clean 這個 task。

需要注意的是,rootProject 與其旗下的各個子工程組成了一個樹形結構,但是這顆樹的高度也僅僅被限定為了兩層。

2、getSubprojects

getSubprojects 表示擷取目前工程下所有子工程的執行個體,示例代碼如下所示:

/**
 * getAllsubproject 使用示例
 */
           

同 getAllprojects 的用法一樣,getSubprojects 方法傳回了一個包含子 project 的 Set 集合,這裡我們直接使用 each 方法将各個子 project 的名字列印出來。其運作結果如下所示:

可以看到,同樣在 Gradle 的配置階段輸出了子工程的名字。

3、getParent

getParent 表示 擷取目前 project 的父類,需要注意的是,如果我們在根工程中使用它,擷取的父類會為 null,因為根工程沒有父類,是以這裡我們直接在 app 的 build.gradle 下編寫下面的示例代碼:

...
           

可以看到,這裡輸出了 app project 目前的父類,即 Awesome-WanAndroid project。

4、getRootProject

如果我們想在根工程僅僅擷取目前的 project 執行個體該怎麼辦呢?直接使用 getRootProject 即可在任意 build.gradle 檔案擷取目前根工程的 project 執行個體,示例代碼如下所示:

/**
 * 4、getRootProject 使用示例
 */
           

5、project

project 表示的是 指定工程的執行個體,然後在閉包中對其進行操作。在使用之前,我們有必要看看 project 方法的源碼,如下所示:

    /**
     * 
           

Locates a project by path and configures it using the given closure. If the path is relative, it is      * interpreted relative to this project. The target project is passed to the closure as the closure's delegate.

     *      * @param path The path.      * @param configureClosure The closure to use to configure the project.      * @return The project with the given path. Never returns null.      * @throws UnknownProjectException If no project with the given path exists.      */     Project project(String path, Closure configureClosure);

可以看到,在 project 方法中兩個參數,一個是指定工程的路徑,另一個是用來配置該工程的閉包。下面我們看看如何靈活地使用 project,示例代碼如下所示:

/**
 * 5、project 使用示例
 */
           

使用熟練之後,我們通常會采用注釋2處的寫法。

6、allprojects

allprojects 表示 用于配置目前 project 及其旗下的每一個子 project,如下所示:

/**
 * 6、allprojects 使用示例
 */
           

在 allprojects 中我們一般用來配置一些通用的配置,比如上面最常見的全局倉庫配置。

7、subprojects

subprojects 可以 統一配置目前 project 下的所有子 project,示例代碼如下所示:

/**
 * 7、subprojects 使用示例:
 *    給所有的子工程引入 将 aar 檔案上傳置 Maven 伺服器的配置腳本
 */
           

在上述示例代碼中,我們會先判斷目前 project 旗下的子 project 是不是庫,如果是庫才有必要引入 publishToMaven 腳本。

3、project 屬性

目前,在 project 接口裡,僅僅預先定義了 七個 屬性,其源碼如下所示:

幸運的是,Gradle 提供了 ext 關鍵字讓我們有能力去定義自身所需要的擴充屬性。有了它便可以對我們工程中的依賴進行全局配置。下面,我們先從配置的遠古時代講起,以便讓我們對 gradle 的 全局依賴配置有更深入的了解。

ext 擴充屬性

1、遠古時代

在 AS 剛出現的時候,我們的依賴配置代碼是這樣的:

2、刀耕火種

但是這種直接寫值的方式顯示是不規範的,是以,後面我們使用了這種方式:

def mCompileSdkVersion = 27
           

3、鐵犁牛耕

如果每一個子 project 都需要配置相同的 Version,我們就需要多寫很多的重複代碼,是以,我們可以利用上面我們學過的 subproject 和 ext 來進行簡化:

// 在根目錄下的 build.gradle 中
           

4、工業時代

使用 subprojects 方法來定義通用的擴充屬性還是存在着很嚴重的問題,它跟之前的方式一樣,還是會在每一個子 project 去定義這些被擴充的屬性,此時,我們可以将 subprojects 去除,直接使用 ext 進行全局定義即可:

// 在根目錄下的 build.gradle 中
           

5、電器時代

當項目越來越大的時候,在根項目下定義的 ext 擴充屬性越來越多,是以,我們可以将這一套全局屬性配置在另一個 gradle 腳本中進行定義,這裡我們通常會将其命名為 config.gradle,通用的模闆如下所示:

6、更加智能化的現在

盡管有了很全面的全局依賴配置檔案,但是,在我們的各個子產品之中,還是不得不寫一大長串的依賴代碼,是以,我們可以 使用周遊的方式去進行依賴,其模闆代碼如下所示:

// 在各個 moulde 下的 build.gradle 腳本下
           

也許未來随着 Gradle 的不斷優化會有更加簡潔的方式,如果你有更好地方式,我們可以來探讨一番。

在 gradle.properties 下定義擴充屬性

除了使用 ext 擴充屬性定義額外的屬性之外,我們也可以在 gradle.properties 下定義擴充屬性,其示例代碼如下所示:

// 在 gradle.properties 中
           

4、檔案相關 API

在 gradle 中,檔案相關的 API 可以總結為如下 兩大類:

1)、路徑擷取 API getRootDir() getProjectDir() getBuildDir() 2)、檔案操作相關 API 檔案定位 檔案拷貝 檔案樹周遊

1)、路徑擷取 API

關于路徑擷取的 API 常用的有 三種,其示例代碼如下所示:

/**
 * 1、路徑擷取 API
 */
           

然後,我們執行 ./gradlew clean,輸出結果如下所示:

2)、檔案操作相關 API

1、檔案定位

常用的檔案定位 API 有 file/files,其示例代碼如下所示:

// 在 rootProject 下的 build.gradle 中
           

2、檔案拷貝

常用的檔案拷貝 API 為 copy,其示例代碼如下所示:

/**
 * 2、檔案拷貝
 */
           

3、檔案樹周遊

我們可以 使用 fileTree 将目前目錄轉換為檔案數的形式,然後便可以擷取到每一個樹元素(節點)進行相應的操作,其示例代碼如下所示:

/**
 * 3、檔案樹周遊
 */
           

5、其它 API

1、依賴相關 API

根項目下的 buildscript

buildscript 中 用于配置項目核心的依賴。其原始的使用示例與簡化後的使用示例分别如下所示:

原始的使用示例
buildscript { 
           
簡化後的使用示例

app moudle 下的 dependencies

不同于 根項目 buildscript 中的 dependencies 是用來配置我們 Gradle 工程的插件依賴的,而 app moudle 下的 dependencies 是用來為應用程式添加第三方依賴的。關于 app moudle 下的依賴使用這裡我們 需要注意下 exclude 與 transitive 的使用 即可,示例代碼如下所示:

2、外部指令執行

我們一般是 使用 Gradle 提供的 exec 來執行外部指令,下面我們就使用 exec 指令來 将目前工程下新生産的 APK 檔案拷貝到 電腦下的 Downloads 目錄中,示例代碼如下所示:

}

4 Task

隻有 Task 才可以在 Gradle 的執行階段去執行(其實質是執行的 Task 中的一系列 Action),是以 Task 的重要性不言而喻。

1、從一個例子 🌰 出發

首先,我們可以在任意一個 build.gradle 檔案中可以去定義一個 Task,下面是一個完整的示例代碼:

// 1、聲明一個名為 JsonChao 的 gradle task
           

首先,在注釋1處,我們聲明了一個名為 JsonChao 的 gradle task。

接着,在注釋2處,在 JsonChao task 閉包内輸出了 hello~,這裡的代碼将會執行在 gradle 生命周期的第二個階段,即配置階段。

然後,在注釋3處,這裡 給 task 附帶一些了一些執行動作(Action),即 doFirst 與 doLast,它們閉包内的代碼将執行在 gradle 生命周期的第三個階段,即執行階段。

對于 doFirst 與 doLast 這兩個 Action,它們的作用分别如下所示:

  • doFirst:表示 task 執行最開始的時候被調用的 Action。
  • doLast:表示 task 将執行完的時候被調用的 Action。

需要注意的是,doFirst 和 doLast 是可以被執行多次的。

最後,注釋4處,我們可以看到,除了注釋1、2、3處這種将聲明與配置、Action 分别定義的方式之外,也可以直接将它們結合起來。在這裡我們又定義了一個 Android task,它依賴于 JsonChao task,也就是說,

必須先執行完 JsonChao task,才能 去執行 Android task,由此,它們之間便組成了一個 有向無環圖:JsonChao task => Android task。

執行 Android 這個 gradle task 可以看到如下輸出結果:

:JsonChao
           

2、Task 的定義及配置

Task 常見的定義方式有 兩種,示例代碼如下所示:

// Task 定義方式1:直接通過 task 函數去建立(在 "()" 可以不指定 group 與 description 屬性)
           

定義完上述 Task 之後再同步項目,即可看到對應的 Task Group 及其旗下的 Tasks,如下圖所示:

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

Task 的屬性

需要注意的是,不管是哪一種 task 的定義方式,在 "()" 内我們都可以配置它的一系列屬性,如下:

'JsonChao3', 
           

目前 官方所支援的屬性 可以總結為如下表格:

選型 描述 預設值
"name" task 名字 無,必須指定
"type" 需要建立的 task Class DefaultTask
"action" 當 task 執行的時候,需要執行的閉包 closure 或 行為 Action null
"overwrite" 替換一個已存在的 task false
"dependsOn" 該 task 所依賴的 task 集合 []
"group" 該 task 所屬組 null
"description" task 的描述資訊 null
"constructorArgs" 傳遞到 task Class 構造器中的參數 null

使用 "$" 來引用另一個 task 的屬性

在這裡,我們可以 在目前 task 中使用 "$" 來引用另一個 task 的屬性,示例代碼如下所示:

使用 ext 給 task 自定義需要的屬性

當然,除了使用已有的屬性之外,我們也可以 使用 ext 給 task 自定義需要的屬性,代碼如下所示:

使用 defaultTasks 關鍵字辨別預設執行任務

此外,我們也可以 使用 defaultTasks 關鍵字 來将一些任務辨別為預設的執行任務,代碼如下所示:

"Gradle_First", 
           

注意事項

每個 task 都會經曆 初始化、配置、執行 這一套完整的生命周期流程。

3、Task 的執行詳解

Task 通常使用 doFirst 與 doLast 兩個方式用于在執行期間進行操作。其示例代碼如下所示:

// 使用 Task 在執行階段進行操作
           

Task 執行實戰

接下來,我們就使用 doFirst 與 doLast 來進行一下實戰,來實作 計算 build 執行期間的耗時,其完整代碼如下所示:

// Task 執行實戰:計算 build 執行期間的耗時
           

4、Task 的依賴和執行順序

指定 Task 的執行順序有 三種 方式,如下圖所示:

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

1)、dependsOn 強依賴方式

dependsOn 強依賴的方式可以細分為 靜态依賴和動态依賴,示例代碼如下所示:

靜态依賴

動态依賴

// Task 動态依賴方式
           

2)、通過 Task 指定輸入輸出

我們也可以通過 Task 來指定輸入輸出,使用這種方式我們可以 高效地實作一個 自動維護版本釋出文檔的 gradle 腳本,其中輸入輸出相關的代碼如下所示:

首先,我們定義了一個 WirteTask,然後,在注釋1處,指定了輸出檔案為 destFile, 并寫入版本資訊到 XML 檔案。

接着,定義了一個 readTask,并在注釋2處,指定輸入檔案為上一個 task(即 writeTask) 的輸出檔案。

最後,在注釋3處,使用 dependsOn 将這兩個 task 關聯起來,此時輸入與輸出的順序是會先執行寫入,再執行讀取。這樣,一個輸入輸出的實際案例就實作了。如果想要檢視完整的實作代碼,請檢視 Awesome-WanAndroid 的 releaseinfo.gradle 腳本。

此外,在 McImage 中就利用了 dependsOn 的方式将自身的 task 插入到了 Gradle 的建構流程之中,關鍵代碼如下所示:

// inject task
           

通過 API 指定依賴順序

除了 dependsOn 的方式,我們還可以在 task 閉包中通過 mustRunAfter 方法指定 task 的依賴順序,需要注意的是,在最新的 gradle api 中,mustRunAfter 必須結合 dependsOn 強依賴進行配套使用,其示例代碼如下所示:

// 通過 API 指定依賴順序
           

5、Task 類型

除了定義一個新的 task 之外,我們也可以使用 type 屬性來直接使用一個已有的 task 類型(很多文章都說的是繼承一個已有的類,不是很準确),比如 Gradle 自帶的 Copy、Delete、Sync task 等等。示例代碼如下所示:

// 1、删除根目錄下的 build 檔案
           

6、挂接到建構生命周期

我們可以使用 gradle 提供的一系列生命周期 API 去挂接我們自己的 task 到建構生命周期之中,比如使用 afterEvaluate 方法 将我們第三小節定義的 writeTask 挂接到 gradle 配置完所有的 task 之後的時刻,示例代碼如下所示:

// 在配置階段執行完之後執行 writeTask
           

需要注意的是,配置完成之後,我們需要在 app moudle 下引入我們定義的 releaseinfo 腳本,引入方式如下:

5SourceSet

SourceSet 主要是 用來設定我們項目中源碼或資源的位置的,目前它最常見的兩個使用案例就是如下 兩類:

  • 1)、修改 so 庫存放位置。
  • 2)、資源檔案分包存放。

1、修改 so 庫存放位置

我們僅需在 app moudle 下的 android 閉包下配置如下代碼即可修改 so 庫存放位置:

2、資源檔案分包存放

同樣,在 app moudle 下的 android 閉包下配置如下代碼即可将資源檔案進行分包存放:

此外,我們也可以使用如下代碼 将 sourceSets 在 android 閉包的外部進行定義:

6 Gradle 指令

Gradle 的指令有很多,但是我們通常隻會使用如下兩種類型的指令:

  • 1)、擷取建構資訊的指令。
  • 2)、執行 task 的指令。

1、擷取建構資訊的指令

// 1、按自頂向下的結構列出子項目的名稱清單
           

2、執行 task 的指令

正常的用于執行 task 的指令有 四種,如下所示:

// 1、用于執行多個 task 任務
           

而對于子目錄下定義的 task,我們通常會使用如下的指令來執行它:

// 1、使用 -b 執行 app 目錄下定義的 task
           

7 總結

至此,我們就将 Gradle 的核心 API 部分講解完畢了,這裡我們再來回顧一下本文的要點,如下所示:

一、Gradle 優勢 1、更好的靈活性 2、更細的粒度 3、更好的擴充性 4、更強的相容性 二、Gradle 建構生命周期 1、初始化階段 2、配置階段 3、執行階段 4、Hook Gradle 各個生命周期節點 5、擷取建構各個階段、任務的耗時情況 三、Project 1、Project 核心 API 分解 2、Project API 3、project 屬性 4、檔案相關 API 5、其它 API 四、Task 1、從一個例子 🌰 出發 2、Task 的定義及配置 3、Task 的執行詳解 4、Task 的依賴和執行順序 5、Task 類型 6、挂接到建構生命周期 五、SourceSet 1、修改 so 庫存放位置 2、資源檔案分包存放 六、Gradle 指令 1、擷取建構資訊的指令 2、執行 task 的指令

Gradle 的核心 API 非常重要,這對我們高效實作一個 Gradle 插件無疑是必不可少的。因為 隻有紮實基礎才能走的更遠,願我們能一同前行。

參考連結:

1、《慕課網之Gradle3.0自動化項目建構技術精講+實戰》6 - 8章

2、Gradle DSL API 文檔

3、Android Plugin DSL API 文檔

4、Gradle DSL => Project 官方 API 文檔

5、Gradle DSL => Task 官方 API 文檔

6、Gradle腳本基礎全攻略

7、全面了解Gradle - 執行時序

8、全面了解Gradle - 定義Task

9、掌控 Android Gradle

10、Gradle基礎 - 建構生命周期和Hook技術

推薦閱讀:

打破你的認知,Java除以0一定會崩潰嗎? 這些年,我所經曆的所有面試 Android View 體系竟然還能這麼了解?

android studio離線配置gradle插件_吹爆系列:深度探索 Gradle 自動化建構技術參考連結:

掃一掃 關注我的公衆号

如果你想要跟大家分享你的文章,歡迎投稿~

┏(^0^)┛明天見!