Gradle學習系列之八——構建多個Project


  在本系列上篇文章中,我們講到了Gradle的依賴管理,在本篇文章中,我們將講到如何構建多個Project。

 

  請通過以下方式下載本系列文章的Github示例代碼:

git clone https://github.com/davenkin/gradle-learning.git

 


 

  Gradle為每個build.gradle都會創建一個相應的Project領域對象,在編寫Gradle腳本時,我們實際上是在操作諸如Project這樣的Gradle領域對象。在多Project的項目中,我們會操作多個Project領域對象。Gradle提供了強大的多Project構建支持。

  要創建多Project的Gradle項目,我們首先需要在根(Root)Project中加入名為settings.gradle的配置文件,該文件應該包含各個子Project的名稱。比如,我們有一個根Project名為root-project,它包含有兩個子Project,名字分別為sub-project1和sub-project2,此時對應的文件目錄結構如下:

root-project/ sub-project1/ build.gradle sub-project2/ build.gradle build.gradle settings.gradle

 

  root-project本身也有自己的build.gradle文件,同時它還擁有settings.gradle文件位於和build.gradle相同的目錄下。此外,兩個子Project也擁有他們自己的build.gradle文件。

  要將sub-project1和sub-project2加入到root-project的子Project中,我們需要在settings.gradle中加入:

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

 

  接下來,我們來定義一個Task用於顯示每個Project各自的名稱。我們可以在每個build.gradle進行定義,但是這卻是一種比較笨的方法,此時我們也完全沒有享受到Gradle的多Project構建功能所帶來的好處。在Gradle中,我們可以通過根Project的allprojects()方法將配置一次性地應用於所有的Project,當然也包括定義Task。比如,在root-project的build.gradle中,我們可以做以下定義:

allprojects { apply plugin: 'idea' task allTask << { println project.name } }

   

  以上Gradle腳本將閉包中的代碼應用在所有的Project中,包括root-project本身。我們首先將應用了idea Plugin用於生成IntelliJ工程,其次我們定義了名為allTask的Task,該Task應用於每個Project,作用是輸出各個Project的名稱。執行“gradle allTask”,命令行輸出如下:

:allTask root-project :sub-project1:allTask sub-project1 :sub-project2:allTask sub-project2

 

  我們看到,該allTask對於每個Project都執行了一次,在執行時輸出了當前Project的名稱。

  除了allprojects()之外,Project還提供了subprojects()方法用於配置所有的子Project(不包含根Project)。比如,我們可以定義Task來只輸出各個子Project的名字:

subprojects { task subTask << { println project.name } }

 

  執行“gradle subTask”,命令行輸出如下:

:sub-project1:subTask sub-project1 :sub-project2:subTask sub-project2

 

  此時的輸出中不再包含root-project的名字。

  上文中已經提到,在Gradle腳本中,我們實際上是在操作一些領域對象,因此我們可以將groovy的所有語言特性用在Gradle的領域對象上,比如我們可以對Project進行過濾:

configure(allprojects.findAll { it.name.startsWith('sub') }) { subTask << { println 'this is a sub project' } }

   

  在上面的代碼中,我們先找到所有Project中名字以“sub”開頭的Project,然后再對這些Project進行配置,在配置中,我們向這些Project的subTask中加入了一條額外的打印語句。

  此時如果再執行“gradle subTask”,命令行輸出如下:

:sub-project1:subTask sub-project1 this is a sub project :sub-project2:subTask sub-project2 this is a sub project

   

  到此為止,我們所有的Task定義工作都是在root-project中進行的,而sub-project1和sub-project2中的build.gradle文件依然什么都沒有。事實上,我們可以將所有對子Project的配置均放在根Project中進行。在上面的例子中,我們通過allprojects()和subprojects()將所有的子Project都包含在了配置之內,其實我們還可以對單個Project進行單獨配置。比如,在root-project的build.gradle中加入:

project(':sub-project1') { task forProject1 << { println 'for project 1' } }

 

  以上腳本向sub-project1中加入了名為forProject1的Task,在執行“gradle forProject1”時,終端輸出如下:

:sub-project1:forProject1 for project 1

 

  這里有一個問題:我們是在root-project下執行的命令,因此照理說Gradle會認為forProject1是定義在所有的Project上,而此時只有sub-project1才擁有該Task,Gradle應該拋出異常指示在root-project和sub-project2上找不到該Task才對,為什么它還是執行成功了呢?原因在於:只有當一個Task沒有在任何Project中定義時,Gradle才會將其當做異常。否則,Gradle會在所有擁有該Task的Project上執行該Task。

  一旦有了多個Project,他們之間便會存在着依賴關系。Gradle的Project之間的依賴關系是基於Task的,而不是整個Project的。

  現在,讓我們來看一個Project依賴的例子。比如sub-project1中有taskA和taskB,taskA依賴於taskB:

task taskA << { println 'this is taskA from project 1' } task taskB << { println 'this is taskB from project 1' } taskA.dependsOn taskB

 

  在執行“gradle taskA”時,終端輸出:

:sub-project1:taskB this is taskB from project 2 :sub-project1:taskA this is taskA from project 1

 

  這個很容易理解,兩個Task都是屬於sub-project1的。但是,讓我們再向其中加入一些復雜性。我們在sub-project2中定義taskC和taskD,然后使taskA再依賴於taskC,又使taskB依賴於taskD:

//sub-project1:
taskA.dependsOn ':sub-project2:taskC' taskB.dependsOn ':sub-project2:taskD'

//sub-project2:
task taskC << { println 'this is taskC from project 2' } task taskD << { println 'this is taskD from project 2' }

 

  此時再執行“gradle taskA”,終端輸出如下:

:sub-project2:taskD this is taskD from project 2 :sub-project1:taskB this is taskB from project 1 :sub-project2:taskC this is taskC from project 2 :sub-project1:taskA this is taskA from project 1

   分析一下:taskA依賴於taskB,而taskB又依賴於taskD,所以sub-project1的taskD首先得到了執行,然后再執行sub-project1的taskB。之后,又由於taskA依賴於taskC,故Gradle再次轉向sub-project1執行taskC,最后才執行taskA。

  下一篇文章中,我們將講到如何自定義Task類型。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM