鍍金池/ 教程/ Android/ 基本組件
Groovy 介紹
腳本類(lèi)、文件 I/O 和 XML 操作
更多
一些前提知識(shí)
Gradle 工作流程
基本組件
題外話
總結(jié)
Gradle 編程模型及 API 實(shí)例詳解
閉包
Gradle 介紹
閑言構(gòu)建
Groovy 中的數(shù)據(jù)類(lèi)型

基本組件

基本組件

Gradle 是一個(gè)框架,它定義一套自己的游戲規(guī)則。我們要玩轉(zhuǎn) Gradle,必須要遵守它設(shè)計(jì)的規(guī)則。下面我們來(lái)講講 Gradle 的基本組件:

Gradle 中,每一個(gè)待編譯的工程都叫一個(gè) Project。每一個(gè) Project 在構(gòu)建的時(shí)候都包含一系列的 Task。比如一個(gè) Android APK 的編譯可能包含:Java 源碼編譯 Task、資源編譯 Task、JNI 編譯 Task、lint 檢查 Task、打包生成 APK 的 Task、簽名 Task 等。

一個(gè) Project 到底包含多少個(gè) Task,其實(shí)是由編譯腳本指定的插件決定。插件是什么呢?插件就是用來(lái)定義 Task,并具體執(zhí)行這些 Task 的東西。

剛才說(shuō)了,Gradle 是一個(gè)框架,作為框架,它負(fù)責(zé)定義流程和規(guī)則。而具體的編譯工作則是通過(guò)插件的方式來(lái)完成的。比如編譯 Java 有 Java 插件,編譯 Groovy 有 Groovy 插件,編譯 Android APP 有 Android APP 插件,編譯 Android Library 有 Android Library 插件

好了。到現(xiàn)在為止,你知道 Gradle 中每一個(gè)待編譯的工程都是一個(gè) Project,一個(gè)具體的編譯過(guò)程是由一個(gè)一個(gè)的 Task 來(lái)定義和執(zhí)行的。

一個(gè)重要的例子

下面我們來(lái)看一個(gè)實(shí)際的例子。這個(gè)例子非常有代表意義。圖 22 是一個(gè)名為 posdevice 的目錄。這個(gè)目錄里包含 3 個(gè) Android Library 工程,2 個(gè) Android APP 工程。

http://wiki.jikexueyuan.com/project/deep-android-gradle/images/23.jpg" alt="" />

在圖 22 的例子中:

  • CPosDeviceSdk、CPosSystemSdk、CPosSystemSdkxxxImpl 是 Android Library。其中,CPosSystemSdkxxxImpl 依賴 CPosSystemSdk
  • CPosDeviceServerApk 和 CPosSdkDemo 是 Android APP。這些 App 和 SDK 有依賴關(guān)系。CPosDeviceServerApk 依賴 CPosDeviceSdk,而 CPosSdkDemo 依賴所有的 Sdk Library。

請(qǐng)回答問(wèn)題,在上面這個(gè)例子中,有多少個(gè) Project?

請(qǐng)回答問(wèn)題,在上面這個(gè)例子中,有多少個(gè) Project?

請(qǐng)回答問(wèn)題,在上面這個(gè)例子中,有多少個(gè) Project?

答案是:每一個(gè) Library 和每一個(gè) App 都是單獨(dú)的 Project。根據(jù) Gradle 的要求,每一個(gè) Project 在其根目錄下都需要有一個(gè) build.gradle。build.gradle 文件就是該 Project 的編譯腳本,類(lèi)似于 Makefile。

看起來(lái)好像很簡(jiǎn)單,但是請(qǐng)注意:posdevice 雖然包含 5 個(gè)獨(dú)立的 Project,但是要獨(dú)立編譯他們的話,得:

  • cd 某個(gè) Project 的目錄。比如 cd CPosDeviceSdk
  • 然后執(zhí)行 gradle xxxx(xxx 是任務(wù)的名字。對(duì) Android 來(lái)說(shuō),assemble 這個(gè) Task 會(huì)生成最終的產(chǎn)物,所以 gradle assemble)

這很麻煩啊,有 10 個(gè)獨(dú)立 Project,就得重復(fù)執(zhí)行 10 次這樣的命令。更有甚者,所謂的獨(dú)立 Project 其實(shí)有依賴關(guān)系的。比如我們這個(gè)例子。

那么,我想在 posdevice 目錄下,直接執(zhí)行 gradle assemble,是否能把這 5 個(gè) Project 的東西都編譯出來(lái)呢?

答案自然是可以。在 Gradle 中,這叫 Multi-Projects Build。把 posdevice 改造成支持 Gradle 的 Multi-Projects Build 很容易,需要:

  • 在 posdevice 下也添加一個(gè) build.gradle。這個(gè) build.gradle 一般干得活是:配置其他子 Project 的。比如為子 Project 添加一些屬性。這個(gè) build.gradle 有沒(méi)有都無(wú)所屬。
  • 在 posdevice 下添加一個(gè)名為 settings.gradle。這個(gè)文件很重要,名字必須是 settings.gradle。它里邊用來(lái)告訴 Gradle,這個(gè) multiprojects 包含多少個(gè)子 Project。

來(lái)看 settings.gradle 的內(nèi)容,最關(guān)鍵的內(nèi)容就是告訴 Gradle 這個(gè) multiprojects 包含哪些子 projects:

[settings.gradle]
//通過(guò) include 函數(shù),將子 Project 的名字(其文件夾名)包含進(jìn)來(lái)  
include  'CPosSystemSdk' , 'CPosDeviceSdk' ,
       'CPosSdkDemo','CPosDeviceServerApk', 'CPosSystemSdkWizarPosImpl'

強(qiáng)烈建議:

如果你確實(shí)只有一個(gè) Project 需要編譯,我也建議你在目錄下添加一個(gè) settings.gradle。我們團(tuán)隊(duì)內(nèi)部的所有單個(gè) Project 都已經(jīng)改成支持 Multiple-Project Build 了。改得方法就是添加 settings.gradle,然后 include 對(duì)應(yīng)的 project 名字。

另外,settings.gradle 除了可以 include 外,還可以設(shè)置一些函數(shù)。這些函數(shù)會(huì)在 gradle 構(gòu)建整個(gè)工程任務(wù)的時(shí)候執(zhí)行,所以,可以在 settings 做一些初始化的工作。比如:我的 settings.gradle 的內(nèi)容:

//定義一個(gè)名為 initMinshengGradleEnvironment 的函數(shù)。該函數(shù)內(nèi)部完成一些初始化操作  
//比如創(chuàng)建特定的目錄,設(shè)置特定的參數(shù)等  
def initMinshengGradleEnvironment(){
    println "initialize Minsheng Gradle Environment ....."
    ......//干一些 special 的私活....
    println "initialize Minsheng Gradle Environment completes..."
}
//settings.gradle 加載的時(shí)候,會(huì)執(zhí)行 initMinshengGradleEnvironment
initMinshengGradleEnvironment()
//include 也是一個(gè)函數(shù):  
include 'CPosSystemSdk' , 'CPosDeviceSdk' , 
      'CPosSdkDemo','CPosDeviceServerApk', 'CPosSystemSdkWizarPosImpl'

gradle 命令介紹

1.gradle projects 查看工程信息

到目前為止,我們了解了 Gradle 什么呢?

  • 每一個(gè) Project 都必須設(shè)置一個(gè) build.gradle 文件。至于其內(nèi)容,我們留到后面再說(shuō)。
  • 對(duì)于 multi-projects build,需要在根目錄下也放一個(gè) build.gradle,和一個(gè) settings.gradle。
  • 一個(gè) Project 是由若干 tasks 來(lái)組成的,當(dāng) gradle xxx 的時(shí)候,實(shí)際上是要求 gradle 執(zhí)行 xxx 任務(wù)。這個(gè)任務(wù)就能完成具體的工作。
  • 當(dāng)然,具體的工作和不同的插件有關(guān)系。編譯 Java 要使用 Java 插件,編譯 Android APP 需要使用 Android APP 插件。這些我們都留待后續(xù)討論

gradle 提供一些方便命令來(lái)查看和 Project,Task 相關(guān)的信息。比如在 posdevice 中,我想看這個(gè) multi projects 到底包含多少個(gè)子 Project:

執(zhí)行 gradle projects,得到圖 23:

http://wiki.jikexueyuan.com/project/deep-android-gradle/images/24.jpg" alt="" />

你看,multi projects 的情況下,posdevice 這個(gè)目錄對(duì)應(yīng)的 build.gradle 叫 Root Project,它包含 5 個(gè)子 Project。

如果你修改 settings.gradle,使得 include 只有一個(gè)參數(shù),則 gradle projects 的子 project 也會(huì)變少,比如圖 24:

http://wiki.jikexueyuan.com/project/deep-android-gradle/images/25.jpg" alt="" />

2.gradle tasks 查看任務(wù)信息

查看了 Project 信息,這個(gè)還比較簡(jiǎn)單,直接看 settings.gradle 也知道。那么 Project 包含哪些 Task 信息,怎么看呢?圖 23,24 中最后的輸出也告訴你了,想看某個(gè) Project 包含哪些 Task 信息,只要執(zhí)行:

gradle project-path:tasks 就行。注意,project-path 是目錄名,后面必須跟冒號(hào)。

對(duì)于 Multi-project,在根目錄中,需要指定你想看哪個(gè) poject 的任務(wù)。不過(guò)你要是已經(jīng) cd 到某個(gè) Project 的目錄了,則不需指定 Project-path。

來(lái)看圖 25:

http://wiki.jikexueyuan.com/project/deep-android-gradle/images/26.jpg" alt="" />

圖 25 是 gradle CPosSystemSdk:tasks 的結(jié)果。

cd CPossystemSdk

gradle tasks 得到同樣的結(jié)果

CPosSystemSdk 是一個(gè) Android Library 工程,Android Library 對(duì)應(yīng)的插件定義了好多 Task。每種插件定義的 Task 都不盡相同,這就是所謂的 Domain Specific,需要我們對(duì)相關(guān)領(lǐng)域有比較多的了解。

這些都是后話,我們以后會(huì)詳細(xì)介紹。

3.gradle task-name 執(zhí)行任務(wù)

圖 25 中列出了好多任務(wù),這時(shí)候就可以通過(guò) gradle 任務(wù)名來(lái)執(zhí)行某個(gè)任務(wù)。這和 make xxx 很像。比如:

  • gradle clean 是執(zhí)行清理任務(wù),和 make clean 類(lèi)似。

  • gradle properites 用來(lái)查看所有屬性信息。

gradle tasks 會(huì)列出每個(gè)任務(wù)的描述,通過(guò)描述,我們大概能知道這些任務(wù)是干什么的.....。然后 gradle task-name 執(zhí)行它就好。

這里要強(qiáng)調(diào)一點(diǎn):Task 和 Task 之間往往是有關(guān)系的,這就是所謂的依賴關(guān)系。比如,assemble task 就依賴其他 task 先執(zhí)行,assemble 才能完成最終的輸出。

依賴關(guān)系對(duì)我們使用 gradle 有什么意義呢?

如果知道 Task 之間的依賴關(guān)系,那么開(kāi)發(fā)者就可以添加一些定制化的 Task。比如我為 assemble 添加一個(gè) SpecialTest 任務(wù),并指定 assemble 依賴于 SpecialTest。當(dāng) assemble 執(zhí)行的時(shí)候,就會(huì)先處理完它依賴的 task。自然,SpecialTest 就會(huì)得到執(zhí)行了... 大家先了解這么多,等后面介紹如何寫(xiě) gradle 腳本的時(shí)候,這就是調(diào)用幾個(gè)函數(shù)的事情,Nothing Special!