Gradle腳本基礎全攻略

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流php

1 背景

在開始Gradle以前請務必保證本身已經初步瞭解了Groovy腳本,特別是閉包規則,若是還不瞭解Groovy則能夠先看《Groovy腳本基礎全攻略》這一篇博客速成一下Groovy基礎,而後再看此文便可。關於Gradle速成乾貨基礎詳情也請參考Geadle官方網站,很差意思我太Low了。css

這裏寫圖片描述

Gradle核心是基於Groovy的領域特定語言(DSL,具體概念參見《Groovy腳本基礎全攻略》),具備很是好的擴展性,因此無論是簡單的獨立項目仍是大型的多項目構建它都能高效的提升構建任務,尤爲對多項目支持是很是牛逼的;Gradle還提供了局部構建功能,譬如構建一個單獨子項目時它會構建這個子項目依賴的全部子項目;固然了他對遠程倉庫和本地庫的支持也很到位;哎呀,總以後面你就明白他的牛逼之處了。html

既然Gradle核心是Groovy,Groovy本質又是Java,因此很明顯能夠發現Gradle環境必須依賴JDK與Groovy庫,具體以下:java

  • JDK版本必須是JDK6以上;git

  • 由於Gradle自帶Groovy庫, 因此已安裝的Groovy會被Gradle忽略;github

具體Gradle環境配置好了之後以下圖:web

這裏寫圖片描述

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流正則表達式

2 Gradle DSL基礎

Gradle的實質是配置腳本,執行一種類型的配置腳本時就會建立一個關聯的對象,譬如執行Build script腳本就會建立一個Project對象,這個對象其實就是Gradle的代理對象。下面給出來各類類型Gradle對應的對象類型:spring

腳本類型 關聯對象類型
Build script Project
Init script Gradle
Settings script Settings


Gradle的三種主要對象解釋以下:編程

  • Project對象:每一個build.gradle會轉換成一個Project對象。

  • Gradle對象:構建初始化時建立,整個構建執行過程當中只有這麼一個對象,通常不多去修改這個默認配置腳本。

  • Settings對象:每一個settings.gradle會轉換成一個Settings對象。

能夠看見,當咱們編寫指定類型Gradle腳本時咱們能夠直接使用關聯對象的屬性和方法;固然了,每一個腳本也都實現了Script接口,也就是說咱們也能夠直接使用Script接口的屬性與方法。

2-1 構建腳本Build script(Project)

在Gradle中每一個待編譯的工程都是一個Project(每一個工程的build.gradle對應一個Project對象),每一個Project在構建的時候都包含一系列Task,這些Task中不少又是Gradle的插件默認支持的。

PS:所謂的咱們編寫Gradle腳本,實質大多數時候都是在編寫構建腳本Build script,因此說Project和Script對象的屬性和方法等API很是重要。

每個Project對象和build.gradle一一對應,一個項目在構建時都具有以下流程:

  1. 爲當前項目建立一個Settings類型的實例。

  2. 若是當前項目存在settings.gradle文件,則經過該文件配置剛纔建立的Settings實例。

  3. 經過Settings實例的配置建立項目層級結構的Project對象實例。

  4. 最後經過上面建立的項目層級結構Project對象實例去執行每一個Project對應的build.gradle腳本。

2-2 初始化腳本Init script(Gradle)和設置腳本Settings script(Settings)

Gradle對象:

初始化腳本Init script(Gradle)相似於Gradle的其餘類型腳本,這種腳本在構建開始以前運行,主要的用途是爲接下來的Build script作一些準備工做。咱們若是須要編寫初始化腳本Init script,則能夠把它按規則放置在USER_HOME/.gradle/相關目錄下。譬如:

這裏寫圖片描述

初始化腳本的Gradle對象表明了Gradle的調運,咱們能夠經過調用Project對象的getGradle()方法得到Gradle實例對象。

Settings對象:

在對工程進行配置(譬如多項目樹構建)時Settings實例與settings.gradle文件一一對應,它用來進行一些項目設置的配置。這個文件通常放置在工程的根目錄。譬如:

這裏寫圖片描述

2-3 Build生命週期

Gradle的構建腳本生命週期具有三大步,以下:

這裏寫圖片描述

能夠看見,生命週期其實和上面構建腳本Build script的執行流程是能夠關聯上的。有了這個流程圖咱們接下里詳細看下每一個過程。

settings.gradle文件:

除了構建腳本文件,Gradle還定義了一個約定名稱的設置文件(默認爲settings.gradle)。該文件在初始化階段被執行,對於多項目構建必須保證在根目錄下有settings.gradle文件,對於單項目構建設置文件是可選的,不過建議仍是寫上。

以下是單項目構建的一個例子:

//settings.gradle println 'This is executed during the initialization phase.'
  • 1
  • 2
  • 1
  • 2
//build.gradle println 'This is executed during the configuration phase.' task configured { println 'This is also executed during the configuration phase.' } task test << { println 'This is executed during the execution phase.' } task testBoth { doFirst { println 'This is executed first during the execution phase.' } doLast { println 'This is executed last during the execution phase.' } println 'This is executed during the configuration phase as well.' }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

運行構建結果:

> gradle test testBoth
This is executed during the initialization phase. This is executed during the configuration phase. This is also executed during the configuration phase. This is executed during the configuration phase as well. :test This is executed during the execution phase. :testBoth This is executed first during the execution phase. This is executed last during the execution phase. BUILD SUCCESSFUL Total time: 1 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Gradle多項目構建:

多項目構建老是須要指定一個樹根,樹中的每個節點表明一個項目,每個Project對象都指定有一個表示在樹中位置的路徑;在設置文件中咱們還可使用一套方法來自定義構建項目樹。

//分層佈局的多項目構建settings.gradle文件 include 'project1', 'project2:child', 'project3:child1'
  • 1
  • 2
  • 1
  • 2

上面例子中把project的路徑做爲了include方法的參數,譬如上面的’project3:child1’參數就指定了物理路徑的project3/child1(project3/child1是相對於多項目根路徑的相對路徑),這也同時意味着會建立’project3’和’project3:child1’兩個project。

//平面佈局的多項目構建settings.gradle文件 includeFlat 'project3', 'project4'
  • 1
  • 2
  • 1
  • 2

上面例子中includeFlat方法接受目錄名做爲參數,可是特別注意,這些項目目錄必須是根目錄的兄弟目錄。

固然了,設置文件中建立的多項目樹實際上是由項目描述符來描述的,咱們能夠在設置文件中隨時修改這些描述符。以下:

//settings.gradle rootProject.name = 'main' project(':projectA').projectDir = new File(settingsDir, '../my-project-a') project(':projectA').buildFileName = 'projectA.gradle'
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

能夠看見,如上例子經過描述符更更名稱和項目目錄,而且創建了一個項目的文件。

Gradle構建初始化Initialization:

在初始化階段若是咱們在根路徑下直接指明settings.gradle文件和相關配置則構建初始化就會直接按照咱們的設置去構建項目,若是咱們沒指明settings.gradle文件則Gradle會以必定的規則去尋找settings.gradle文件,而後依據尋找結果的不一樣去決定如何構建項目。

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

3 Gradle構建基礎

經過上一章能夠知道,每個Gradle構建都是由一個或多個project構成,每個project都是由一個或多個tasks構成,每一個task的實質實際上是一些更加細化的構建(譬如編譯class、建立jar文件等)。

任務task基礎:

以下例子咱們先來直觀感覺一下task的概念,具體細節後面會探討:

//建立一個名爲build.gradle的文件 task hello { doLast { println 'Hello world!' } } //這是快捷寫法,用<<替換doLast,後面解釋 task hl << { println 'Hello world!' } //建立upper的task,使用Groovy語言編寫 task upper << { String someString = 'mY_nAmE' println "Original: " + someString println "Upper case: " + someString.toUpperCase() }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

經過以下命令運行構建上面名爲hello的task,具體以下:

xxx@XXX:~/$ gradle hello :hello Hello world! BUILD SUCCESSFUL Total time: 1.037 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

能夠看見,gradle命令會在當前目錄中查找一個叫build.gradle的構建腳本文件,這個構建腳本定義了一個叫作hello的獨立task,而且添加了一個action,咱們執行了這個task就獲得了想要的結果。

在這裏再多嘴一句,咱們看下task有無action的區別,以下:

//有Action的task task actionTask << { println 'I am actionTask' } //無Action的task task noActionTask { println 'I am noActionTask' } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

必定要記住,在上面這個例子中若是task沒有加<<則這個任務在腳本初始化initialization階段(即不管執行啥task都被執行,具體參見上一章的第一個例子)被執行,若是加了<<則在gradle actionTask後才執行。由於沒有加<<則閉包在task函數返回前會執行,而加了<<則變成調用actionTask.doLast(),因此會等到gradle actionTask時執行。

任務task依賴:

咱們經過上面task基礎感覺的例子能夠發現,一個build.gradle文件中定義多個task互相沒有關係,決定執行的是咱們gradle命令後面跟的task名字;那咱們要是讓他們之間有依賴關係咋辦呢?以下:

task taskX(dependsOn: 'taskY') << { println 'taskX' } task taskY << { println 'taskY' }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

運行結果以下:

xxx@XXX:~/$ gradle taskX :taskY taskY :taskX taskX BUILD SUCCESSFUL Total time: 1.039 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

動態任務task:

咱們還能夠在Gradle中使用Groovy來建立動態task,以下:

4.times { counter -> task "task$counter" << { println "I'm task number $counter" } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

運行結果以下:

xxx@XXX:~/$ gradle task1 :task1 I'm task number 1 BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用已存在任務task:

咱們除過在上面定義任務task時指明依賴之外還能夠經過API爲任務加入一個依賴,以下:

4.times { counter -> task "task$counter" << { println "I'm task number $counter" } } task0.dependsOn task2, task3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

運行結果以下:

xxx@XXX:~/$ gradle task0 :task0 I'm task number 2 I'm task number 3 I'm task number 0 BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

或者咱們還能夠經過API爲任務加入一些新行爲,以下:

task hello << { println 'Hello Earth' } hello.doFirst { println 'Hello Venus' } hello.doLast { println 'Hello Mars' } hello << { println 'Hello Jupiter' }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

運行結果以下:

xxx@XXX:~/$ gradle hello :hello Hello Venus Hello Earth Hello Mars Hello Jupiter BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

能夠發現,doFirst和doLast能夠被執行屢次,<<操做符實質就是doLast。

任務task短標記:

咱們能夠經過美圓符將一個task做爲另外一個task的屬性,以下:

task hello << {
    println 'Hello world!' } hello.doLast { println "Greetings from the $hello.name task." }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

執行結果以下:

xxx@XXX:~/$ gradle hello :hello Hello world! Greetings from the hello task. BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

能夠看見,上面腳本中使用的name實際上是任務的默認屬性, 表明當前任務的名稱。

自定義任務task屬性:

咱們還能夠給任務task加入自定義的屬性,以下例子:

task myTask { ext.myProperty = "myValue" } task printTaskProperties << { println myTask.myProperty }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

執行結果以下:

xxx@XXX:~/$ gradle printTaskProperties :printTaskProperties myValue BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

定義默認任務task:

Gradle容許在腳本中定義一個或多個默認任務,以下:

defaultTasks 'clean', 'run' task clean << { println 'Default Cleaning!' } task run << { println 'Default Running!' } task other << { println "I'm not a default task!" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

執行結果以下:

xxx@XXX:~/$ gradle :clean,run Default Cleaning! Default Running! BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

4 Gradle依賴管理基礎

大多數項目都不是徹底獨立的,它們須要依賴其餘項目進行編譯等,Gradle容許你告訴它你項目的依賴關係,以便找到這些依賴關係,並在你的構建中維護這些依賴關係,依賴關係可能須要從遠程的Maven等倉庫中下載,也多是在本地文件系統中,或者是經過多項目構建另外一個構建,咱們稱這個過程爲依賴解析。

Gradle依賴聲明:

關於依賴聲明不解釋,直接給個例子,以下:

apply plugin: 'java' repositories { mavenCentral() } dependencies { compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final' testCompile group: 'junit', name: 'junit', version: '4.+' }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Gradle依賴配置:

在Gradle中依賴能夠組合成configurations(配置),一個配置簡單地說就是一系列的依賴,通俗說也就是依賴配置;咱們可使用它們聲明項目的外部依賴,也能夠被用來聲明項目的發佈。下面咱們給出幾種Java插件中常見的配置,以下:

  • compile 
    用來編譯項目源代碼的依賴;

  • runtime 
    在運行時被生成的類須要的依賴,默認項,包含編譯時的依賴;

  • testCompile

    編譯測試代碼依賴,默認項,包含生成的類運行所需的依賴和編譯源代碼的依賴;

  • testRuntime

    運行測試所須要的依賴,默認項,包含上面三個依賴;

各類各樣的插件支持許多標準的配置,咱們還能夠定義本身的配置。

Gradle外部依賴:

咱們能夠用Gradle聲明許多種依賴,其中有一種是外部依賴(external dependency),它是在當前構建以外的一種依賴,通常存放在遠程(譬如Maven)或本地的倉庫裏。以下是一個外部依賴的例子:

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final' }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

能夠看見,引用一個外部依賴須要用到group、name、version屬性。上面的寫法還有一種簡寫,以下規則:

group:name:version
  • 1
  • 1

這是一個簡寫的例子:

dependencies { compile 'org.hibernate:hibernate-core:3.6.7.Final' }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Gradle倉庫:

有了上面的外部依賴,你指定會想Gradle是咋找到那些外部依賴文件的。其實Gradle會在一個倉庫(repository)裏找這些依賴文件,倉庫其實就是不少依賴文件的集合服務器, 他們經過group、name、version進行歸類存儲,好在Gradle能夠解析好幾種不一樣的倉庫形式(譬如Maven等),可是Gradle默認不提早定義任何倉庫,咱們必須手動在使用外部依賴以前定義本身的倉庫。

下面是一個使用MavenCentral倉庫的例子:

repositories { mavenCentral() }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

這是一個使用遠程Maven倉庫的例子:

repositories {
    maven {
        url "http://repo.mycompany.com/maven2" } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

這是一個使用本地文件系統裏庫的例子:

repositories {
    ivy {
        // URL can refer to a local directory url "../local-repo" } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

固然了,一個項目能夠有好幾個庫,Gradle會根據依賴定義的順序在各個庫裏尋找它們,在第一個庫裏找到了就不會再在第二個庫裏找它了,不然在第二個庫找。

Gradle發佈artifacts:

依賴配置也能夠用來發布文件,咱們能夠經過在uploadArchives任務里加入倉庫來完成。下面是一個發佈到Maven 庫的例子,Gradle將生成和上傳pom.xml,以下:

apply plugin: 'maven' uploadArchives { repositories { mavenDeployer { repository(url: "file://localhost/tmp/myRepo/") } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

5 Gradle命令

多任務調用命令:

gradle task1 task2 [...]
  • 1
  • 1

排除任務命令:

gradle -x task1 task2 [...]
  • 1
  • 1

失敗後繼續執行構建命令:

只要有任務調用失敗Gradle默認就會中斷執行,咱們可使用–continue選項在一次調用中不中斷執行,而後發現全部失敗緣由。

簡化任務名命令:

當咱們調用某個任務時若是名字太長咱們能夠採用簡化操做,可是必須保證能夠惟一區分出該任務的字符,譬如:

//簡寫 gradle -x t1 //替換 gradle -x task1
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

選擇執行構建命令:

調用gradle命令默認會構建當前目錄下的build.gradle文件,咱們可使用-b參數選擇其餘目錄的構建文件且當使用此參數時settings.gradle將不會生效。以下:

//選擇文件構建subdir/myproject.gradle
task hello << {
    println "using build file '$buildFile.name' in '$buildFile.parentFile.name'." }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

執行過程:

xxx@XXX:~/$ gradle -b subdir/myproject.gradle hello :hello using build file 'myproject.gradle' in 'subdir'. BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此外咱們還可使用-p參數來指定構建的目錄,譬如在多項目構建中能夠用-p替代-b參數。以下執行過程:

xxx@XXX:~/$ gradle -p subdir hello :hello using build file 'build.gradle' in 'subdir'. BUILD SUCCESSFUL Total time: 1.397 secs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

獲取構建信息:

  • gradle projects命令:列出子項目名稱列表。
  • gradle tasks命令:列出項目中全部任務。
  • gradle help –task someTask命令:能夠顯示指定任務的詳細信息。
  • gradle dependencies命令:列出項目的依賴列表,全部依賴會根據任務區分,以樹型結構展現。

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

6 編寫Gradle腳本

Gradle是以Groovy語言爲基礎,基於DSL語法的自動化構建工具,一個構建腳本可以包含任何Groovy語言元素,每一個腳本都是UTF-8編碼的文件。

6-1 Project對象API

前面咱們說過,Gradle在構建腳本中定義了一個project,對於構建腳本中每一個project其實Gradle都建立了一個 Project類型的對象來關聯,當構建腳本執行時它會去配置所關聯的Project對象;構建腳本中每一個被調用的方法和屬性都委託給了當前Project對象。

以下咱們看一個使用Project屬性的例子:

println name println project.name
  • 1
  • 2
  • 1
  • 2

上面兩個println語句的輸出是同樣的;因爲name屬性沒有在當前腳本中定義,因此能夠像第一個那樣使用自動委託 ,一般咱們使用第二中寫法。

Project對象提供了一些標準的屬性,咱們能夠在構建腳本中很方便的使用他們,以下:

Name Type Default Value
project Project Project實例對象
name String 項目目錄的名稱
path String 項目的絕對路徑
description String 項目描述
projectDir File 包含構建腳本的目錄
build File projectDir/build
group Object 未具體說明
version Object 未具體說明
ant AntBuilder Ant實例對象

具體關於Project的方法詳情參閱Project的API文檔。這裏咱們給出Project的apply方法的一個例子,以下:

//加載一個gradle文件 apply from: rootProject.getRootDir().getAbsolutePath() + "/common.gradle" 
  • 1
  • 2
  • 1
  • 2

6-2 Script對象API

當Gradle執行一個腳本時它會將這個腳本編譯爲實現了Script的類(在上篇博客《Groovy腳本基礎全攻略》Groovy的本質編譯class代碼那塊有介紹),也就是說全部的屬性和方法都是在Script的接口中聲明。

6-3 Gradle對象API

關於Gradle對象的詳細屬性和API介紹點我便可。這裏直接給出一個使用Gradle對象的例子,以下:

這裏寫圖片描述

6-4 Gradle變量聲明

在Gradle腳本中有兩種類型的變量能夠聲明,以下:

  • 局部變量
  • 擴展變量

局部變量使用關鍵字def聲明,它只在聲明的地方可見,以下:

def dest = "dest" task copy(type: Copy) { form "source" into dest }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在Gradle中全部被加強的對象能夠擁有自定義屬性(譬如projects、tasks、source sets等),使用ext擴展塊能夠一次添加多個屬性。以下:

apply plugin: "java" ext { springVersion = "3.1.0.RELEASE" emailNotification = "build@master.org" } sourceSets.all { ext.purpose = null } sourceSets { main { purpose = "production" } test { purpose = "test" } plugin { purpose = "production" } } task printProperties << { println springVersion println emailNotification sourceSets.matching { it.purpose == "production" }.each { println it.name} } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上面咱們用一個ext擴展塊向Project對象添加兩個擴展屬性,當這些擴展屬性被添加後,它們就像預約義的屬性同樣能夠被讀寫。

6-5 Gradle中Groovy使用

這個沒啥說的,具體能夠參考《Groovy腳本基礎全攻略》這篇博客,裏面有詳細介紹。咱們這裏粗略總結回憶一下便可:

  • Groovy會自動將一個屬性的引用轉換爲相應的getter/setter方法。

  • Groovy調用方法時圓括號無關緊要。

  • Groovy爲List和Map集合提供了一些操做捷徑,譬如apply plugin:’java’中的plugin:’java’其實就是Groovy中的Map,apply是一個方法,省略了括弧而已。

哎呀,詳細的仍是去看前一篇博客吧。

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

7 Gradle文件操做基礎

實際使用Gradle過程當中大多數時候須要操做文件,好在Gradle給咱們提供了一些API來快捷處理。

定位文件:

咱們可使用Project.file()方法來定位一個文件獲取File對象(詳情參考Project的API),以下:

//相對路徑 File configFile = file('src/config.xml') //絕對路徑 File configFile = file(configFile.absolutePath) //項目路徑的文件對象 File configFile = file(new File('src/config.xml'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

能夠從Project的API發現file()方法可以接收任何形式的對象參數,它會將參數值轉換爲一個絕對文件對象,一般咱們能夠傳一個String或File實例;若是傳的路徑是絕對路徑,則會被直接構造爲一個文件實例,不然會被構造爲項目目錄加上傳遞目錄的文件對象;固然了,file()方法還能識別URL(譬如file:/some/path.xml等)。

文件集合:

文件集合實際上是一組文件,Gradle使用FileCollection接口表示文件集合,Gradle API中許多類都實現了這個接口,譬如dependency configurations等。獲取FileCollection實例的一種方法是Project.files(),咱們能夠傳遞任何數量的對象參數。以下:

FileCollection collection = files('src/file1.txt', new File('src/file2.txt'), ['src/file3.txt', 'src/file4.txt'])
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

使用迭代操做還能將其轉換爲其餘的一些類型,同時咱們還可使用+操做將兩個文件集合合併,使用-操做對一個文件集合作減法。以下例子:

// 對文件集合進行迭代
collection.each {File file -> println file.name }  // 轉換文件集合爲其餘類型 Set set = collection.files Set set2 = collection as Set List list = collection as List String path = collection.asPath File file = collection.singleFile File file2 = collection as File  // 增長和減小文件集合 def union = collection + files('src/file3.txt') def different = collection - files('src/file3.txt')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

咱們也能夠向files()方法傳遞閉包或者可回調的實例參數,當查詢集合的內容時就會調用它,而後將返回值轉換爲一些文件實例,返回值能夠是files()方法支持的任何類型的對象。以下例子:

task list << {
    File srcDir

    // 使用閉合建立一個文件集合 collection = files { srcDir.listFiles() } srcDir = file('src') println "Contents of $srcDir.name" collection.collect { relativePath(it) }.sort().each { println it } srcDir = file('src2') println "Contents of $srcDir.name" collection.collect { relativePath(it) }.sort().each { println it } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

文件樹:

文件樹能夠表明一個目錄樹結構或一個ZIP壓縮文件的內容,FileTree繼承自FileCollection,因此咱們能夠像處理文件集合同樣處理文件樹,使用Project.fileTree()方法能夠獲得FileTree實例,它會建立一個基於基準目錄的對象。以下:

/以一個基準目錄建立一個文件樹
FileTree tree = fileTree(dir: 'src/main')  // 添加包含和排除規則 tree.include '**/*.java' tree.exclude '**/Abstract*'  // 使用路徑建立一個樹 tree = fileTree('src').include('**/*.java')  // 使用閉合建立一個數 tree = fileTree('src') { include '**/*.java' }  // 使用map建立一個樹 tree = fileTree(dir: 'src', include: '**/*.java') tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml']) tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')  // 遍歷文件樹 tree.each {File file -> println file }  // 過濾文件樹 FileTree filtered = tree.matching { include 'org/gradle/api/**' }  // 合併文件樹A FileTree sum = tree + fileTree(dir: 'src/test')  // 訪問文件數的元素 tree.visit {element -> println "$element.relativePath => $element.file" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

咱們還可使用ZIP或TAR等壓縮文件的內容做爲文件樹,Project.zipTree()和Project.tarTree()方法能夠返回一個FileTree實例。以下:

// 使用路徑建立一個ZIP文件 FileTree zip = zipTree('someFile.zip') // 使用路徑建立一個TAR文件 FileTree tar = tarTree('someFile.tar') //TarTree能夠根據文件擴展名獲得壓縮方式,若是咱們想明確的指定壓縮方式則能夠以下操做 FileTree someTar = tarTree(resources.gzip('someTar.ext'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

指定輸入文件:

Gradle中有些對象的屬性能夠接收一組輸入文件,譬如JavaComplile任務的source屬性(定義編譯的源文件)。以下:

//使用一個File對象設置源目錄 compile { source = file('src/main/java') } //使用一個字符路徑設置源目錄 compile { source = 'src/main/java' } //使用一個集合設置多個源目錄 compile { source = ['src/main/java', '../shared/java'] } //使用FileCollection或者FileTree設置源目錄 compile { source = fileTree(dir: 'src/main/java').matching {include 'org/gradle/api/**'} } //使用閉包設置源目錄 compile { source = { // Use the contents of each zip file in the src dir file('src').listFiles().findAll {it.name.endsWith('.zip')}.collect { zipTree(it) } } } compile { //使用字符路徑添加源目錄 source 'src/main/java', 'src/main/groovy' //使用File對象添加源目錄 source file('../shared/java') //使用閉包添加源目錄 source { file('src/test/').listFiles() } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

複製文件:

咱們可使用複製任務(Copy)進行文件複製操做,複製任務擴展性很強,它能夠過濾複製文件的內容,使用複製任務要提供想要複製的源文件和一個目標目錄,若是要指定文件被複制時的轉換方式則可使用複製規則,複製規則是一個CopySpec接口的實現,咱們使用CopySpec.from()方法指定源文件,CopySpec.into()方法指定目標目錄便可。以下:

task copyTask(type: Copy) {
    from 'src/main/webapp' into 'build/explodedWar' } task anotherCopyTask(type: Copy) {  //複製src/main/webapp目錄下的全部文件 from 'src/main/webapp'  //複製一個單獨文件 from 'src/staging/index.html'  //複製一個任務輸出的文件 from copyTask  //顯式使用任務的outputs屬性複製任務的輸出文件 from copyTaskWithPatterns.outputs  //複製一個ZIP壓縮文件的內容 from zipTree('src/main/assets.zip')  //指定目標目錄 into { getDestDir() } } task copyTaskWithPatterns(type: Copy) { from 'src/main/webapp' into 'build/explodedWar' include '**/*.html' include '**/*.jsp' exclude { details -> details.file.name.endsWith('.html') && details.file.text.contains('staging') } } task copyMethod << { copy { from 'src/main/webapp' into 'build/explodedWar' include '**/*.html' include '**/*.jsp' } }  //在複製時重命名文件 task rename(type: Copy) { from 'src/main/webapp' into 'build/explodedWar'  //使用閉包映射文件名 rename { String fileName -> fileName.replace('-staging-', '') }  // 使用正則表達式映射文件名 rename '(.+)-staging-(.+)', '$1$2' rename(/(.+)-staging-(.+)/, '$1$2') }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

文件同步任務:

同步任務(Sync)繼承自複製任務(Copy),當執行時會複製源文件到目標目錄,而後從目標目錄刪除全部非複製文件。以下:

task libs(type: Sync) { from configurations.runtime into "$buildDir/libs" }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

建立歸檔文件:

使用歸檔任務能夠建立Zip、Tar、Jar、War、Ear等歸檔文件,以下:

apply plugin: 'java' task zip(type: Zip) { from 'src/dist' into('libs') { from configurations.runtime } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

關於文件操做的其餘請參考API文檔。

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

8 Gradle插件

8-1 Gradle插件概述

插件基礎:

關於Gradle支持的插件能夠點我搜索。其實Gradle的核心只是一個空空的框架,所謂的Gradle構建便捷腳本其實都是由插件提供支持的,插件添加了新的任務。在Gradle中通常有兩種類型的插件,以下:

  • 腳本插件 
    是額外的構建腳本,它會進一步配置構建,一般會在構建內部使用。腳本插件能夠從本地文件系統或遠程獲取,若是從文件系統獲取則是相對於項目目錄,若是是遠程獲取則是由HTTP URL指定。

  • 二進制插件 
    是實現了Plugin接口的類,而且採用編程的方式來操縱構建。

插件須要經過Project.apply()方法完成聲明應用,相同的插件能夠應用屢次。以下例子:

//腳本插件 apply from: 'other.gradle' //二進制插件 apply plugin: 'java'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

插件還可使用插件ID,插件的id做爲給定插件的惟一標識符,咱們能夠給插件註冊一個縮寫字符的id。譬以下面例子:

//經過Java插件的id進行引用 apply plugin: JavaPlugin
  • 1
  • 2
  • 1
  • 2

使用構建腳本塊應用插件:

咱們能夠向構建腳本中加入插件的類路徑而後再應用插件和使用插件的任務,以下:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1" } } apply plugin: "com.jfrog.bintray"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Gradle插件拓展:

能夠看見,Gradle實際上是依託於各類插件壯大的,譬如Java插件用來構建Java工程,Android插件用來構建打包Android工程,咱們只須要選擇合適的插件便可,插件會爲咱們提供豐富的任務用來快捷處理構建,具體詳情參考各插件API便可。

8-2 Gradle的Java插件構建實例

上面說了,插件是Gradle的擴展,它會經過某種方式配置咱們的項目(譬如加入一些task);Gradle自帶許多插件,咱們也能夠編寫本身的插件而後開源.,Java 插件就是這樣的一個插件,該插件已經給項目定義了默認的參數(譬如Java源文件位置),因此一般咱們不須要在腳本中加入太多東西。

單個基礎Java項目構建:

//把Java插件加入到項目中,也就是許多預約制的任務被自動加入到了項目裏 apply plugin: 'java'
  • 1
  • 2
  • 1
  • 2

加入上面插件之後Gradle默認但願能在src/main/java路徑下找到源代碼,在 src/test/java路徑下找到測試代碼,任何src/main/resources路徑的文件都會被包含在JAR文件裏,任何src/test/resources路徑的文件都會被加入到classpath中以運行測試代碼,全部的輸出文件將會被建立在構建目錄裏,JAR文件存放在 build/libs文件夾裏。

加入Java插件後咱們能夠經過gradle tasks命令來列出項目的全部任務,這樣就能夠知道Java插件添加了哪些task。經常使用的task以下:

  • build task 
    當運行gradle build命令時Gradle將會編譯和測試你的代碼,而且建立一個包含類和資源的JAR文件。

  • clean task 
    當運行gradle clean命令時Gradle將會刪除build生成的目錄和全部生成的文件。

  • assemble task 
    當運行gradle assemble命令時Gradle將會編譯並打包代碼,可是並不運行單元測試。

  • check task 
    當運行gradle check命令時Gradle將會編譯並測試你的代碼,其餘的插件會加入更多的檢查步驟。

單個具備外部依賴的Java項目構建:

固然了,一個Java項目可能會有許多外部依賴(即調用第三方JAR),爲了在項目裏引用這些 JAR包,咱們須要告訴Gradle去哪裏找他們,好在Gradle支持許多倉庫,這些倉庫能夠被用來提取或者放置依賴,咱們能夠很方便的從這些倉庫中取得第三方Jar包。以下:

//加入Maven倉庫 repositories { mavenCentral() }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

接着加入一些編譯階段來自於mavenCentral倉庫的依賴,以下:

dependencies {
    //編譯階段 compile group: 'commons-collections', name: 'commons-collections', version: '3.2' //測試編譯階段 testCompile group: 'junit', name: 'junit', version: '4.+' }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定製構建項目:

Java插件給項目加入了一些屬性,這些屬性已經被賦予了默認的值且已經夠咱們平常使用了,若是咱們以爲這些默認屬性很差也能夠本身修改。以下:

//定製 MANIFEST.MF 文件
sourceCompatibility = 1.5 version = '1.0' jar { manifest { attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

默認Java插件加入的任務是常規性的任務,可是咱們能夠定製任務,譬如咱們能夠設置一個任務的屬性、在任務中加入行爲、改變任務的依賴、徹底重寫一個任務等。以下:

//測試階段加入一個系統屬性 test { systemProperties 'property': 'value' }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

關於哪些屬性是可用的問題,咱們可使用gradle properties命令列出項目的全部屬性。

發佈JAR文件:

一般JAR文件須要在某個地方發佈,咱們能夠經過Gradle方便的進行發佈,譬以下面例子將發佈到一個本地的目錄,以下:

//uploadArchives task
uploadArchives {
    repositories {
       flatDir {
           dirs 'repos' } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

多Java項目構建:

在Gradle中爲了定義一個多項目構建咱們須要建立一個設置文件(settings.gradle),設置文件放在源代碼的根目錄,它用來指定要包含哪一個項目且名字必須叫作settings.gradle。以下例子:

//多項目工程結構樹: multiproject/ api/ services/webservice/ shared/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
//多項目構建settings.gradle文件 include "shared", "api", "services:webservice", "services:shared"
  • 1
  • 2
  • 1
  • 2

對於大多數多項目構建有一些配置對全部項目都是通用的,因此咱們將在根項目裏定義一個這樣的通用配置(配置注入技術 configuration injection)。 根項目就像一個容器,subprojects方法遍歷這個容器的全部元素而且注入指定的配置。以下:

//多項目構建通用配置 subprojects { apply plugin: 'java' apply plugin: 'eclipse-wtp' repositories { mavenCentral() } dependencies { testCompile 'junit:junit:4.11' } version = '1.0' jar { manifest.attributes provider: 'gradle' } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

能夠看見,上面通用配置把Java插件應用到了每個子項目中。

咱們還能夠在同一個構建里加入項目之間的依賴,這樣能夠保證他們的前後關係。以下:

//api/build.gradle dependencies { compile project(':shared') }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

至此基礎的Java插件使用就OK了,深刻的請自行查看API。

【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流

4 Gradle基礎總結

到此Gradle的基礎知識就徹底介紹完了,咱們對Gradle的框架也有了一個直觀的認識。其實編寫Gradle無非也就是對類的屬性和方法進行調運操做,至於如何調運操做依據具體插件而異,核心的生命週期和幾個對象實例搞明白基本上就能駕馭Gradle腳本了,其餘的無非就是熟練度和API查找。

相關文章
相關標籤/搜索