1. 程式人生 > >從零開始學習Gradle之三---多專案構建

從零開始學習Gradle之三---多專案構建

   隨著資訊化的快速發展,IT專案變得越來越複雜,通常都是由多個子系統共同協作完成。對於這種多系統、多專案的情況,很多構建工具都已經提供了不錯的支援,像maven、ant。Gradle除了借鑑了ant或者maven的繼承的方式定義子專案,也提供了一種更為方便的集中配置的方式,大大減少了構建帶來的複雜度。除此之外,Gradle還提供了清晰的Project樹模型來對映多專案的組織結構。下面,讓我們瞭解一下如何使用Gradle構建多專案。

1. 多專案定義及結構

 在Gradle中,使用檔案settings.gradle定義當前專案的子專案,格式如下所示: 

include 'sub-project1', 'sub-project2', 'sub-project3',

它表示在當前的專案下建立三個子專案,分別為'sub-project1', 'sub-project2', 'sub-project3'。預設情況下,每個子專案的名稱對應著當前作業系統目錄下的一個子目錄。

當Gradle執行時,會根據settings.gradle的配置情況,構建一個單根節點的專案樹。其中的每個子節點代表一個專案(Project),每個專案都有一個唯一的路徑表示它在當前樹中的位置,路徑的定義方式類似:

Root:<Level1-子節點>:<Level2-子節點>:<Level3-子節點>

也可以簡寫成“:<Level1-子節點>:<Level2-子節點>:<Level3-子節點>”。藉助這種路徑的定義方式,我們可以在build.gradle去訪問不同的子專案。另外,對於單專案,實際上是一種特殊的、只存在根節點,沒有子節點的專案樹。

例如,我們有個產品A,包括以下幾個元件core,web,mobile。分別代表"核心邏輯"、"網站"、“手機客戶端”。 因為每個元件是獨立的部分,這個時候最好我們能定義多個子專案,讓每個子專案分別管理自己的構建。於是我們可以這樣定義A/settings.gradle

include 'core', 'web', 'mobile'

按照之前描述的,core元件對應A/core目錄,web元件對應A/web目錄,mobile元件對應A/mobile目錄。接下來,我們就可以在每個元件內部,定義build.gradle負責管理當前元件的構建。

Gradle提供了一個內建的task 'gradle projects',可以 幫助我們檢視當前專案所包含的子專案,下面讓我們看看gradle projects的輸出結果:

$ gradle projects
:projects
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'A'
+--- Project ':core'
+--- Project ':mobile'
\--- Project ':web

結果一目瞭然,首先是Root級別的專案A,然後是A下面的子專案'core', 'mobile', 'mobile'

最終的檔案以及目錄結構如下所示:

A
   --settings.gradle
   --build.gradle
   --core
     --build.gradle
   --web
      --build.gradle
   --mobile
      --build.gradle

如果你不喜歡這種預設的結構,也可以按照如下方式定義子專案的名稱和物理目錄結構:

include(':core)
project(':core').projectDir = new File(settingsDir, 'core-xxx') 

include(':web)
project(':web').projectDir = new File(settingsDir, 'web-xxx') 

include(':mobile)
project(':mobile').projectDir = new File(settingsDir, 'mobile-xxx') 

在這個例子中,子專案core實際上對應的物理目錄為A/core-xxx,web實際上對應的是A/web-xxx,mobile也類似。

雖然我們更改了子專案的物理目錄結構,不過由於我們在build.gradle中使用的是類似 “ :<SubProject>”的方式訪問對應的子專案,所以目錄結構的改變,對我們Gradle的構建指令碼並不會產生影響。

接下來,考慮一個更復雜的情況,隨著產品的發展,mobile這個元件慢慢的劃分成了Android和IOS兩個部分,這時我們只需要在目錄A/mobile下定義新的settings.gradle,並加入如下部分:

include 'android', 'ios'

現在,mobile元件下將存在兩個新的子專案 "android"和"ios"

於是,這時候'gradle projects'的目錄結構就變成

A
   --settings.gradle
   --core
      --build.gradle
   --web
      --build.gradle
   --mobile
      --settings.gradle
      --ios
        --build.gradle
      --android
        --build.gradle

2. 多專案的集中配置

對於大多數構建工具,對於子專案的配置,都是基於繼承的方式。Gradle除了提供繼承的方式來設定子專案,還提供了另外一種集中的配置方式,方便我們統一管理子專案的資訊。下面看一個例子,開啟A/build.gradle,輸入如下部分:

allprojects {
    task hello << {task -> println "I'm $task.project.name" }
}
subprojects {
    hello << {println "- I am the sub project of A"}
}
project(':core').hello << {
      println "- I'm the core component and provide service for other parts."
}

對於上面所示的程式碼,已經很表意了:

allprojects{xxx}  這段程式碼表示,對於所有的project,Gradle都將定義一個名稱是hello的Task { println "I'm $task.project.name"} 。

subprojects{xxxx}的這段程式碼表示,對於所有的子project,將在名稱為hello的Task上追加Action {println "- I am the sub project of A"}

注意:關於Task和Action的關係,請看我之前寫的本系列的第一部分。

project(':core')的這段程式碼表示,對於名稱為core的project,將在名稱為hello的Task上追加Action { println "- I'm the core component and provide service for other parts." }


3. 多專案的Task執行

之前我們已經瞭解了多專案的結構以及如何通過路徑去訪問子專案。現在讓我們看看如何使用Gradle來執行多專案。

在Gradle中,當在當前專案上執行gradle <Task>時,gradle會遍歷當前專案以及其所有的子專案,依次執行所有的同名Task,注意:子專案的遍歷順序並不是按照setting.gradle中的定義順序,而是按照子專案的首字母排列順序。

基於剛才的例子,如果我們在根目錄下,執行gradle hello,那麼所有子專案的“hello” Task都會被執行。如果我們在mobile目錄下執行gradle hello,那麼mobile、android以及IOS的“hello” Task都會被執行。關於該例子的執行結果,這裡就不貼出來了。大家如果有興趣的話可以試試。

4. 總結
這篇文章主要描述了使用Gradle管理多專案的知識。相比Ant或者Maven,Gradle提供了更靈活的配置方式。更重要的是,Gradle還提供了很多內建的Task幫助我們檢視或者管理專案。這次就先聊到這裡,下次我們來看看Gradle的生命週期。