原文Gradle Plugin User Guide - Android Tools Project Site
samples see bottom of New Build System
參考Gradle For Android Training Coursehtml
這篇文檔是基於0.9版本的Gradle插件,1.0之前的版本因爲不兼容,可能會有所不一樣java
新構建系統的目標是:android
Gradle是一個高級構建系統和構建工具,容許經過插件自定義構建邏輯git
如下一些功能使得咱們選擇Gradle:api
Gradle項目經過項目根目錄下的 build.gradle 文件來描述構建過程數組
最簡單的Java項目構建文件 build.gradle安全
apply plugin: 'java'
這個腳本應用了Gradle的Java插件。這個插件了提供構建和測試Java應用的全部功能服務器
最簡單的Android項目的構建文件包含如下內容: 網絡
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.11.1' } } apply plugin: 'android' android { compileSdkVersion 19 buildToolsVersion "19.0.0" }
Note(譯註): 最新的android插件聲明
apply plugin: 'com.android.application'
閉包
在這個Android構建腳本里包含了三個主要內容:
buildscript { ... }
配置了驅動構建過程的代碼。在這個案例中,聲明瞭使用Maven倉庫,以及一個Maven文件(artifact)的依賴路徑。這個文件就是包含了Android Gradle插件的庫,版本爲0.11.1
而後,android
插件被應用,像以前的Java插件同樣
最後,android { ... }
配置了anroid構建過程須要的參數。這也是Adnroid DSL的入口。默認的狀況下,只有編譯目標SDK版本,和構建工具版本是必須的。在腳本中,對應的是compileSdkVersion
和buildtoolsVersion
屬性。compileSdkVersion
和舊編譯系統中project.properties
文件中的target
屬性對應。這個新屬性compileSdkVersion
能夠是一個int值(API Level)或者一個和以前的target
屬性值同樣的字符串
重點: 你應該只應用android插件,同時應用java插件會致使構建錯誤
注意: 你一樣須要一個local.properties
文件來指明SDK的路徑,和build.gradle
在同一路徑下,在文件中使用sdk.dir
屬性指明。或者,你能夠設置ANDROID_HOME
環境變量。二者是一致的,你能夠選擇一種你喜歡的方式。
前面的android構建腳本使用了默認的文件夾目錄結構。Gradle遵循約定優於配置
的原則,在可能的狀況下提供了合理的默認配置參數。
基本的項目包含兩個「source sets」組件。main source code
和test code
,位於如下的目錄中:
src/main/ src/androidTest/
在這些目錄中,都存在目錄對應源碼組件
無論是Java仍是Android插件,源碼目錄和資源目錄都以下 :
java/ resources/
對於Android插件,還有特有的文件和目錄
AndroidManifest.xml res/ assets/ aidl/ rs/ jni/
Note: src/androidTest/AndroidManifest.xml
不是必須的,會自動被建立。
當默認項目結構不合適的時候,能夠配置項目目錄。根據Gradle文檔,能夠經過下面的腳本從新配置Java項目的sourceSets:
sourceSets { main { java { srcDir 'src/java' } resources { srcDir 'src/resources' } } }
Note: srcDir 會添加指定的目錄到源文件目錄列表中(這在Gradele文檔中沒有說起,可是其實是這樣的)。
爲了替換默認的源文件目錄列表,可使用srcDirs
來指定目錄數組。這也是一種不一樣的使用方式:
sourceSets { main.java.srcDirs = ['src/java'] main.resources.srcDirs = ['src/resources'] }
更多的信息,參考Gradle文檔中的Java插件內容
Android插件使用類似的語法,可是因爲使用是本身的sourceSets
,相應的目錄在(build.gradle
文件中的)android對象中指定
下面是一個示例,它使用舊項目的源碼結構,而且將androidTest sourceSet映射到tests目錄
android { sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } androidTest.setRoot('tests') } }
Note: 因爲舊的結構將全部的源文件 (java, aidl, renderscript, and java資源文件)放在一個目錄裏,咱們須要映射這些sourceSet組件到src目錄。
Note: setRoot() 方法將整個sourceSet(包含子目錄)指向新的目錄。好比上面,將src/androidTest/*
指向了 tests/*
以上是Android特有的,若是配置在Java sourceSets中就沒有做用
‘migrated’ 示例(位於本頁面底部)中展現了這部份內容
在build文件中應用一個插件將自動建立一系列構建任務。Java插件和Android插件都是這樣。任務約定以下:
組合項目輸出
執行全部檢查
執行assemble和check兩個task的全部工做
清理項目輸出
任務assemble
, check
和 build
不會作任何實際的事情。他們只是錨點任務(anchor tasks),插件依賴他們來添加實際執行實際操做的任務。
這樣就不須要考慮項目是什麼類型,使用的是什麼插件,均可以執行一樣的任務。
例如,使用findbugs插件,會建立新的任務,並讓check
依賴這個任務,使得check
被調用時這個任務就會被調用。
在終端(命令行,gradle項目目錄下)中運行下面的任務能夠查詢到高級別的任務:
gradle tasks
運行如下命令能夠看到所有任務和任務依賴關係:
gradle tasks --all
Note: Gradle自動監視一個任務聲明的輸入輸出文件。再次執行構建任務時,若是文件沒有改變,Gradle會指明全部任務爲UP-TO-DATE
,意味着任務不須要執行。這樣的話,任務能夠正確地互相依賴,而不不會致使非必須的構建操做
Java插件主要建立兩個任務,下面是這兩個錨點任務的依賴關係
jar
任務直接或間接地依賴其餘任務:例如classes
任務將編譯Java源碼
testClasses
任務用於編譯測試的,可是這個任務不多被調用,由於test
任務依賴於它(就像依賴classes
任務同樣)
一般來講,你只須要調用assemble
或者check
任務,而不須要調用其餘任務。
你能夠在Gradle Java插件文檔看到Java插件的所有任務和它們的描述
Android插件使用一樣的約定來保持和其餘插件的兼容,而且添加了額外的錨點任務:
assemble
這個任務組織項目的輸出
check
這個項目運行全部檢查
connectedCheck
運行檢查須要一個已鏈接的設備或者模擬器。並在全部已鏈接的設備上異步運行。
deviceCheck
經過APIs鏈接遠程設備並運行檢查。這一般在CI服務器上運行。
build
運行assemble
和check
clean
清理項目輸出
新的錨點任務是必須的,以保證在不須要設備鏈接的狀況下能運行常規檢查。
須要注意的是,build
任務並不依賴deviceCheck
或者connectedCheck
一個Android項目至少有兩個輸出:debug APK 和 release APK。它們每個都有本身的錨點任務來幫助它們完成獨立的構建:
它們都依賴其它任務來完成構建一個apk所須要的多個步驟。assemble
任務依賴這兩個任務,因此調用assemble
會生成兩個APK。
Tip: Gradle支持在命令行中使用camel形式的任務名縮寫。
例如:
gradle aR
和gradle assembleRelease
是同樣的,由於沒有別的任務名有一樣的縮寫
錨點任務check
也有本身的依賴:
最終,插件會爲全部構建類型(debug, release, test)建立install
/uninstall
任務,若是輸出文件能夠安裝的話(必須簽名)。
Android插件提供了大量DSL來直接從構建系統中定製大多數事情。
經過DSL,能夠配置如下manifest屬性:
例如:
android { compileSdkVersion 19 buildToolsVersion "19.0.0" defaultConfig { versionCode 12 versionName "2.0" minSdkVersion 16 targetSdkVersion 16 } }
配置項位於android
元素中的defaultConfig
元素中。
以前版本的Android Plugin使用packageName來配置manifest文件的packageName
屬性。從0.11.1版本開始,你應該在build.gradle文件使用applicationId來配置manifest文件的packageName
屬性。
這是爲了消除Android應用的packageName
(做爲Android應用的ID)和java包名之間的疑義。
在構建文件中定義的強大之處在於它能夠是動態的。
例如,能夠從一個文件中讀取版本名稱,或者使用自定義的邏輯:
def computeVersionName() { ... } android { compileSdkVersion 19 buildToolsVersion "19.0.0" defaultConfig { versionCode 12 versionName computeVersionName() minSdkVersion 16 targetSdkVersion 16 } }
Note: 函數名不要與指定範圍內已經存在的getter方法名衝突。例如,在defaultConfig { ...}
中調用getVersionName()會自動使用defaultConfig.getVersionName(),而不是你自定義的其它getVersionName()。
若是屬性沒有經過DSL設置,那麼默認的屬性值會被使用。下面是默認的屬性值列表:
Property Name | Default value in DSL object | Default value |
---|---|---|
versionCode | -1 | value from manifest if present |
versionName | null | value from manifest if present |
minSdkVersion | -1 | value from manifest if present |
targetSdkVersion | -1 | value from manifest if present |
applicationId | null | value from manifest if present |
testApplicationId | null | applicationId + 「.test」 |
testInstrumentationRunner | null | android.test.InstrumentationTestRunner |
signingConfig | null | null |
proguardFile | N/A (set only) | N/A (set only) |
proguardFiles | N/A (set only) | N/A (set only) |
若是你在構建腳本中使用自定義的邏輯讀取這些屬性,那麼第二列的屬性就很重要。例如,你可能這樣寫:
if (android.defaultConfig.testInstrumentationRunner == null) { // assign a better default... }
若是這個值是null,那麼在構建過程當中會被第三列的默認值替代,可是DSL元素不會包含這個默認值(第三列的值),因此你查詢不到這個值。這是爲了防止解析應用的manifest文件,除非真的必要。
默認狀況下,Android插件會自動設置項目同時構建debug和release版本的應用程序。
這兩個版本的不一樣之處主要在於可否在一個安全設備上調試程序,和APK如何簽名。
debug版本使用一個自動建立的密鑰/證書,並使用已知的name/password來簽名(防止構建過程當中出現請求提示)。release版本在構建過程當中沒有簽名,須要稍後簽名。
這些配置經過一個構建類型(BuildTpye)對象來設置。默認狀況下,debug和release這兩個構建類型都會被建立。
Android插件容許自定義這兩個實例,也容許建立其它構建類型。這些都在buildTypes的DSL容器中配置:
android { buildTypes { debug { applicationIdSuffix ".debug" } jnidebug.initWith(buildTypes.debug) jnidebug { packageNameSuffix ".jnidebug" jniDebuggable true } } }
上面的代碼片斷完成來如下功能:
配置默認的debug
構建類型:
<app appliationId>.debug
,以便在同一設備上同時安裝debug和release版本建立了一個新的名爲jnidebug
的構建類型,是debug構建類型的一個副本
jnidebug
構建類型,容許調試JNI組件,而且添加一個不一樣的包名後綴建立一個新的構建類型就像在buildTypes
容器中使用一個新的元素同樣簡單,能夠經過調用initWith()
或者使用閉包來配置
如下是可能用到的屬性和它們的默認值:
Property name | Default values for debug | Default values for release / other |
---|---|---|
debuggable | true | false |
jniDebuggable | false | false |
renderscriptDebuggable | false | false |
renderscriptOptimLevel | 3 | 3 |
applicationIdSuffix | null | null |
versionNameSuffix | null | null |
signingConfig | android.signingConfigs.debug | null |
zipAlignEnabled | false | true |
minifyEnabled | false | false |
proguardFile | N/A (set only) | N/A (set only) |
proguardFiles | N/A (set only) | N/A (set only) |
除了以上這些屬性,Build Types還能夠經過源碼和資源來影響構建過程。
每個構建類型都會建立一個匹配的sourceSet,默認的路徑爲:
src/<buildtypename>/
這意味這新的構建類型的名字不能是main或者androidTest(這是插件強制要求的),而構建類型的名稱必須是惟一的。
像其它sourceSet同樣,構建類型的sourceSet能夠從新被定向:
android { sourceSets.jnidebug.setRoot('foo/jnidebug') }
另外,每個Build Type都會建立一個assemble<BuildTypeName>
任務。
在前面,assembleDebug
和assembleRelease
已經提到過了,這就是它們的來源。當debug和release構建類型被預建立的時候,它們相關的任務就被自動建立了,好比assembleDebug
和assembleRelease
上面的build.gradle片斷一樣會建立assembleJnidebug
任務,assemble
會像依賴assembleDebug
和assembleRelease
任務同樣依賴assembleJnidebug
。
Tip: 你能夠在命令行下輸入gradle aJ
來運行assembleJnidebug
任務。
可能用到的場景:
BuildType的源碼和資源經過如下方式使用:
對一個應用程序簽名須要如下:
位置,別名,兩個密碼和存儲類型一個組成一個簽名配置(SigningConfig)
默認狀況下,debug
簽名配置使用一個debug keystore,已知的密碼和已知的別名以及別名密碼。
debug keystore位於$HOME/.android/debug.keystore
,若是沒有的話會自動建立一個。
debug
構建類型會自動使用debug
SigningConfig。
能夠建立其它簽名配置或者自定義默認內建配置。經過signingConfigs
DSL容器來配置
android { signingConfigs { debug { storeFile file("debug.keystore") } myConfig { storeFile file("other.keystore") storePassword "android" keyAlias "androiddebugkey" keyPassword "android" } } buildTypes { foo { debuggable true jniDebuggable true signingConfig signingConfigs.myConfig } } }
上面的片斷修改debug keystore的位置到項目根目錄下。這會影響任何使用它的構建類型,在這個案例中,受影響的是debug
構建類型。
這裏也建立了一個新的簽名配置和一個使用這個新簽名配置的行的構建類型。
Note: 只有默認路徑下debug keystore不存在的時候會被自動建立。改變debug keystore的路徑則不會在新的路徑下自動建立debug keystore。建立一個名字不一樣的簽名配置,可是使用默認的debug keystore路徑,會自動建立debug keystore。也就是說,是否自動建立debug keystore,是由keystore的位置決定,而不是配置的名稱。
Note: keystore的路徑一般是項目根目錄的相對路徑,可是也可使用絕對路徑,儘管不推薦這樣(debug keystore除外,由於它會自動被建立)。
**Note: 若是你要把這些文件添加到版本控制系統中,你可能不想把密碼寫在文件中。下面的Stack Overflow鏈接提供了從從控制檯或者環境變量讀取的方法。
http://stackoverflow.com/questions/18328730/how-to-create-a-release-signed-apk-file-using-gradle
咱們之後會更新指南,提供更多的細節**
ProGuard從Gradle plugin for ProGuard 4.10開始支持的(since Gradle plugin 0.4)。若是構建類型的minifyEnabled
屬性被設置爲true,那麼Progruard插件會自動被添加進來,對應的任務也自動被建立。
Note: 從Gradle插件版本0.14.0開始BuildType.runProguard更改成minifyEnabled屬性。具體請參考Release notes
android { buildTypes { release { minifyEnabled true proguardFile getDefaultProguardFile('proguard-android.txt') } } productFlavors { flavor1 { } flavor2 { proguardFile 'some-other-rules.txt' } } }
Variant會使用全部聲明的規則文件,包括聲明在相應的Build Type和flavor中的。
SDK中有兩個默認的規則文件:
它們位於sdk路徑下,使用getDefaultProguardFile()能夠獲取文件的完整路徑。它們除了是否要進行優化以外,其它都是相同的。
構建時能夠自動移除沒有被使用的資源文件。更多詳細信息請查看文檔資源文件壓縮
Gradle項目能夠依賴其它組件,這些組件能夠是外部二進制包,或者其它Gradle項目。
爲了配置一個外部庫jar依賴,你須要在compile
配置中添加一個依賴
dependencies { compile files('libs/foo.jar') } android { ... }
Note: dependencies
DSL元素是標準Gradle API的一部分,並不屬於android
元素。
compile
配置是用來編譯main應用的。任何添加到編譯路徑中的東西都會被打包到最終的apk文件中。
下面是其它一些在添加依賴時可能用到的配置:
compile
: 主moduleandroidTestCompile
: 測試moduledebugCompile
: debug構建類型的編譯releaseCompile
: release構建類型的編譯由於構建一個apk必然有一個相關的構建類型,因此apk一般至少有兩個編譯配置:compile
和<buildtype>Compile
建立一個構建類型時會自動建立一個基於它名字的編譯配置<buildtype>Compile
當你在debug版本里須要使用一個自定義庫(例如記錄crash信息),而release版本不須要,或者他們依賴同一個庫的不一樣版本的時候,會很是有用。
也能夠經過添加一個目錄來依賴目錄下的全部jar文件:
compile fileTree(dir: 'libs', include: ['*.jar'])
Gradle支持從Maven或者Ivy倉庫獲取依賴文件。
首先,必須把倉庫添加到列表中,其次,必須按照Maven或者Ivy的文件聲明規範來聲明依賴。
repositories { mavenCentral() } dependencies { compile 'com.google.guava:guava:11.0.2' } android { ... }
Note: mavenCentral()
是指定倉庫URL的便捷方式。Gradle支持遠程和本地倉庫。
Note: Gradle遵循依賴關係的傳遞性。若是一個被依賴文件也依賴其它文件,那些被依賴的文件也會被拉取下來。
更多關於配置依賴的信息,請查看Gradle用戶指南和DSL文檔
Gradle項目能夠經過多項目設置依賴其它gradle項目。
一個多項目設置一般把全部子項目做爲子目錄放在指定的項目根目錄下。
例如,項目結構以下:
MyProject/ + app/ + libraries/ + lib1/ + lib2/
咱們在這個結構中定義3個項目。Gradle將經過如下名字引用它們:
:app :libraries:lib1 :libraries:lib2
每一個項目都有本身的build.gradle
文件,聲明來它怎樣構建。另外,在根目錄下還有一個settings.gradle
文件,聲明瞭全部的子項目。
目錄結構以下:
MyProject/ | settings.gradle + app/ | build.gradle + libraries/ + lib1/ | build.gradle + lib2/ | build.gradle
settings.gradle
文件的內容十分簡單:
include ':app', ':libraries:lib1', ':libraries:lib2'
指明哪一個文件夾是一個實際的Gradle項目。
:app
項目或許依賴其它庫項目,那麼依賴關係聲明以下:
dependencies { compile project(':libraries:lib1') }
更多關於多項目設置的信息在這裏。
在上面的多項目設置中,:libraries:lib1
和:libraries:lib2
多是Java項目,:app
Android項目將會使用它們輸出的jar文件。
然而,若是你想要共享使用了Android API或者Android資源文件的代碼(在庫項目中使用了Android API或Android資源文件),這些庫項目就不能是常規的Java項目,必須是Android庫項目。
一個庫項目和常規的Android項目很類似,只有不多的區別。
由於構建庫項目和構建應用程序不同,因此使用不一樣的插件。構建庫項目的插件和構建應用程序的插件在內部共享大部分的代碼,而且它們都是由com.android.tools.build.gradle
jar庫提供。
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.5.6' } } apply plugin: 'android-library' android { compileSdkVersion 15 }
這是一個使用API 15編譯的庫項目。SourceSets
和依賴關係的處理跟應用程序項目中同樣,並且定製方式也同樣。
一個庫項目的主要輸出是一個.aar
包(它表明Android的歸檔文件)。它包含編譯好的源碼(例如jar文件或者本地.so文件)以及資源文件(manifest, res, assets)。
一個庫項目也能夠生成一個測試apk來測試,而不依賴應用程序。
因爲使用一樣的錨點任務(assembleDebug
, assembleRelease
),因此在命令行中構建庫項目和普通項目沒有區別。
其他部分,庫項目和應用程序項目同樣。都有構建類型和product flavors,能夠生成多個版本的aar。
要注意的是,多數Build Type配置不適用於庫項目。然而,你能夠定製sourceSet
來改變所依賴庫的內容,不論它是被普通項目使用仍是被測試。
引用一個庫項目和引用其它項目的方式同樣:
dependencies { compile project(':libraries:lib1') compile project(':libraries:lib2') }
Note: 若是你由多個庫項目,那麼順序是很重要的。這和舊構建系統中的project.properties
文件中的依賴順序同樣重要。
默認的狀況下,庫項目只會發佈release變種版本(release variant)。這個版本會被全部引用了庫項目的項目使用,無論它們本身構建的是什麼版本。這是Gradle致使的限制,咱們正努力消除這個限制。
能夠以下控制哪一個版本會被髮布:
android { defaultPublishConfig "debug" }
要注意的是,這個發佈配置名稱必須是完整的variant名稱,release
和debug
這兩個名稱只有在沒有flavor的時候才使用。若是想要在有flavor的時候改變默認的發佈版本,你必須這樣寫:
android { defaultPublishConfig "flavor1Debug" }
發佈庫項目的全部版本也是可能的。咱們計劃在普通的項目依賴項目的工程中容許這種作法,可是因爲Gradle的限制,如今還不能這麼作(咱們也在努力修復這個問題)。
發佈全部版本的功能默認沒有開啓。開啓以下:
android { publishNonDefault true }
必須認識到發佈多個variant版本意味着發佈多個aar文件,而不是在一個aar文件中包含了多個variant版本。每個aar文件就是一個獨立的variant。
發佈一個variant版本意味着構建出了一個可用的aar文件,做爲Gradle項目的輸出文件。這個文件能夠發佈到maven倉庫,或者在其餘項目依賴該庫項目時做爲依賴目標。
Gradle有默認文件的概念。下面這個就使用了默認文件:
compile project(':libraries:lib2')
爲了依賴其餘的發佈版本,你必須指定具體使用哪個:
dependencies { flavor1Compile project(path: ':lib1', configuration: 'flavor1Release') flavor2Compile project(path: ':lib1', configuration: 'flavor2Release') }
重要: 要注意已發佈的配置是完整的variant版本,包含了構建類型,所以引用的時候也必須是完整的。
重要: 當開啓了無默認版本發佈,Maven發佈插件會把這些額外的版本做爲擴展包(按分類器)發佈。這意味着並非真正兼容地發佈到maven倉庫。你應該發佈一個獨立的vatiant到倉庫,或者開啓發布全部配置來支持跨項目依賴。
構建一個測試應用已經內置在應用項目內。不須要再建立單獨的測試項目。
試驗性的單元測試功能支持已經加入到1.1中,具體請看這個頁面。本節其餘部分講述的是」instrumentation tests」
正如前面提到的,緊鄰着main
sourceSet 的就是 androidTest
sourceSet,默認在src/androidTest/
路徑下。
從這個sourceSet 會構建出一個使用Android測試框架,而且能夠部署到設備上的測試apk來測試應用程序。這裏面能夠包含單元測試,集成測試,和後續UI自動化測試。
測試應用的<instrumentation>
節點是自動生成的,可是你也能夠建立一個src/androidTest/AndroidManifest.xml
,並在這個manifest文件中添加其餘組件。
下面是一些測試應用能夠配置的值:
正如前面所看到的,這些在defaultConfig對象中配置:
android { defaultConfig { testPackageName "com.test.foo" testInstrumentationRunner "android.test.InstrumentationTestRunner" testHandleProfiling true testFunctionalTest true } }
在測試應用程序的manifest文件中,instrumentation節點的targetPackage屬性值會自動使用測試應用的package名稱設置,即便這個名稱是經過defaultConfig或者Build Type對象自定義的。這也是manifest文件須要自動生成的一個緣由。
另外,這個測試sourceSet也能夠擁有本身的依賴。
默認狀況下,應用程序和他的依賴會自動添加的測試應用的classpath中,可是也能夠經過如下來擴展:
dependencies { androidTestCompile 'com.google.guava:guava:11.0.2' }
測試應用經過assembleTest
任務來構建。assembleTest不依賴於main中的assemble
任務,須要手動設置運行,不能自動運行。
目前只有一個Build Type被測試。默認狀況下是debug
Build Type,可是這也能夠經過如下自定義配置:
android { ... testBuildType "staging" }
正如前面提到的,檢查經過錨點任務connectedCheck
啓動,這須要一個設備已鏈接。
這個過程依賴於androidTest任務,所以將會運行androidTest。這個task將會執行下面內容:
assembleDebug
和assembleTest
)若是有多於一個鏈接設備,那麼全部測試都會同時運行在全部鏈接設備上。若是其中一個測試失敗,無論是哪個設備,這個構建就失敗。
全部測試結果都被保存爲XML文檔,路徑爲:
build/androidTest-results
(這和常規的JUnit相似,運行結果保存在build/test-results)
一樣,這也能夠自定義配置:
android { ... testOptions { resultsDir = "$project.buildDir/foo/results" } }
android.testOptions.resultsDir
由Project.file(String)得到。
測試Android庫項目的方法與應用項目的測試方法基本同樣。
惟一的不一樣在於整個庫(包括它的依賴)都是自動做爲依賴庫被添加到測試應用中。結果就是測試APK不單隻包含它的代碼,還包含了庫項目本身和庫的全部依賴。
庫的manifest被組合到測試應用的manifest中(和其餘項目引用這個庫時同樣)。
androidTest
變成只是安裝(或者卸載)測試APK(由於沒有其它APK要安裝)。
其它的部分都是相似的。
當運行單元測試的時候,Gradle會輸出一份HTML格式的報告以方便查看結果。
Android plugin也是基於此,而且擴展了HTML報告文件,它將全部鏈接設備的報告都合併到一個文件裏面。
項目將會自動生成測試運行,測試報告默認位置:
build/reports/androidTests
這很是相似於JUnit的報告所在位置build/reports/tests
,其它的報告一般位於build/reports/<plugin>/
這個路徑也能夠經過如下方式自定義:
android { ... testOptions { reportDir = "$project.buildDir/foo/report" } }
報告將會合並運行在不一樣設備上的測試結果。
在一個配置了多個應用或者多個庫項目的項目中,當同時運行全部測試的時候,生成一個單一報告文件記錄全部的測試多是很是有用的。
爲了實現這個目的,須要使用同一個依賴文件中的另外一個插件。能夠經過如下方式添加:
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.5.6' } } apply plugin: 'android-reporting'
這必須添加到項目的根目錄下,例如與settings.gradle文件同個目錄的build.gradle文件中。
而後,在命令行中導航到項目根目錄下,輸入如下命令就能夠運行全部測試併合並全部報告:
gradle deviceCheck mergeAndroidReports --continue
注意:--continue
選項將容許全部測試,即便子項目中的任何一個運行失敗都不會中止。若是沒有這個選項,第一個失敗測試將會終止所有測試的運行,這可能致使一些項目沒有執行過它們的測試。
從0.7.0版本開始,你能夠爲項目中一個特定的variant版本運行lint,也能夠爲全部variant版本都運行lint。它將會生成一個報告描述哪個variant版本中存在着問題。
你能夠經過如下lint選項配置lint。一般狀況下你只須要配置其中一部分,如下列出了全部可以使用的選項:
android { lintOptions { // set to true to turn off analysis progress reporting by lint quiet true // if true, stop the gradle build if errors are found abortOnError false // if true, only report errors ignoreWarnings true // if true, emit full/absolute paths to files with errors (true by default) //absolutePaths true // if true, check all issues, including those that are off by default checkAllWarnings true // if true, treat all warnings as errors warningsAsErrors true // turn off checking the given issue id's disable 'TypographyFractions','TypographyQuotes' // turn on the given issue id's enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' // check *only* the given issue id's check 'NewApi', 'InlinedApi' // if true, don't include source code lines in the error output noLines true // if true, show all locations for an error, do not truncate lists, etc. showAll true // Fallback lint configuration (default severities, etc.) lintConfig file("default-lint.xml") // if true, generate a text report of issues (false by default) textReport true // location to write the output; can be a file or 'stdout' textOutput 'stdout' // if true, generate an XML report for use by for example Jenkins xmlReport false // file to write report to (if not specified, defaults to lint-results.xml) xmlOutput file("lint-report.xml") // if true, generate an HTML report (with issue explanations, sourcecode, etc) htmlReport true // optional path to report (default will be lint-results.html in the builddir) htmlOutput file("lint-report.html") // set to true to have all release builds run lint on issues with severity=fatal // and abort the build (controlled by abortOnError above) if fatal issues are found checkReleaseBuilds true // Set the severity of the given issues to fatal (which means they will be // checked during release builds (even if the lint target is not included) fatal 'NewApi', 'InlineApi' // Set the severity of the given issues to error error 'Wakelock', 'TextViewEdits' // Set the severity of the given issues to warning warning 'ResourceAsColor' // Set the severity of the given issues to ignore (same as disabling the check) ignore 'TypographyQuotes' } }
新構建系統的一個目標就是爲一個應用構建不一樣的版本。
有兩個主要的場景:
也就是說,從同一個項目中生成這些不一樣的apk,而不是使用一個庫工程和2個以上的主應用工程。
一個product flavor
定義了項目構建輸出的一個自定義應用版本。一個單獨項目能夠有不一樣的flavor,來生成不一樣的應用。
這個新概念(flavor)是用來解決不一樣應用版本間差別很小的情形。若是「這是否同一個應用?」的回答是確定的話,這是比使用庫項目更好的作法。
flavor使用productFlavors
這個DSL容器來聲明:
android { .... productFlavors { flavor1 { ... } flavor2 { ... } } }
這裏建立了兩個flavor,分別是 flavor1
和 flavor2
。
注意: flavor的名字不能喝已有的構建類型(Build Type)名字衝突,或者和androidTest
這個sourceSet的名字衝突。
前面已經提到,每個構建類型都會生成一個apk。忘了的話,請看3.4.2
Product Flavors 也會作一樣的事情,實際上,項目輸出來自全部可能的,Build Types和Product Flavors的組合,若是有Product Flavors的話。
每種Build Types和Product Flavors的組合就是一個Build Variant。
例如,默認的debug
和 release
這兩個Build Types,和上面建立的兩個flavor會生成4個Build Variants:
沒有flavor的項目也有Build Variants,使用默認的沒有名字的flavor配置,使得Build Variants列表看起來和 Build Types同樣。
每一個flavor在下面這樣的閉包結構中配置:
android { ... defaultConfig { minSdkVersion 8 versionCode 10 } productFlavors { flavor1 { packageName "com.example.flavor1" versionCode 20 } flavor2 { packageName "com.example.flavor2" minSdkVersion 14 } } }
注意到android.productFlavors.*
和android.defaultConfig
的配置項類型相同,這意味着他們共享相同的屬性。
defaultConfig
爲全部的flavor提供默認的配置,每一個flavor均可以覆蓋配置項的值。上面的例子中,最終的配置以下:
一般,Build Type配置會覆蓋其餘配置。例如Build Type‘的packageNameSuffix
會添加到Product Flavor‘的 packageName
上。
也有一些狀況下,一個配置項能夠同時在Build Type 和 Product Flavor都進行配置,這時,就要具體狀況具體分析了。
例如,signingConfig
就是這樣一個配置項。
能夠設置android.buildTypes.release.signingConfig
讓全部release版本使用同一個SigningConfig,也能夠單獨設置android.productFlavors.*.signingConfig
讓各release使用各自的SigningConfig。
和構建類型相似,產品flavor也能夠經過他們本身的sourceSets影響最終的代碼和資源
在上面的例子中,建立了四個sourceSet:
src/flavor1/
src/flavor2/
src/androidTestFlavor1/
src/androidTestFlavor2/
這些sourceSet 都會用來建立apk,和android.sourceSets.main
以及構建類型的sourceSet一塊兒。
下面是構建apk時,全部sourceSet的處理原則:
最後,和Build Type同樣,Product Flavor還能夠有本身的依賴。例如,flavor包含了一個廣告版本和一個支付版本,那麼就會依賴廣告sdk,而其餘版本不依賴。
dependencies { flavor1Compile "..." }
在這個特別的狀況下,src/flavor1/AndroidManifest.xml
也許須要添加一個網絡權限
每一個variant也會包含額外的sourceset:
src/flavor1Debug/
src/flavor1Release/
src/flavor2Debug/
src/flavor2Release/
這些sourceset比build type的sourceset有更高的優先級,容許variant級別的定製。
前面提到,每一個Build Type有本身的assemble<name>
任務。可是Build Variant是Build Type 和 Product Flavor組合。
當使用Product Flavor的時候,更多的assemble-type任務會被建立出來,分別是:
assemble
任務會構建全部可能的variant版本。
測試多flavor的項目和簡單項目十分相似。
androidTest
sourceset被用來定義全部flavor的通用測試,同時,每一個flavor也能夠有各自的測試。
正如上面提到的,測試各flavor的sourceSet會被建立:
src/androidTestFlavor1/
src/androidTestFlavor2/
一樣,他們也能夠有他們本身的依賴:
dependencies { androidTestFlavor1Compile "..." }
能夠經過錨點任務deviceCheck
來運行測試,或者androidTest
任務(當使用flavor時,它做爲錨點任務)。
每一個flavor有本身的任務運行測試:androidTest<VariantName>
。例如:
相似的,每一個variant都有構建測試apk和安裝/卸載任務。
最後,生成的HTML報告支持按照flavor合併。
測試結果和報告位置以下,首先是每一個flavor版本的,而後是合併的。
改變任一個路徑,只會影響根目錄,仍然會爲每一個flavor和合並後的結果建立子目錄。
某些狀況下,應用可能須要基於多個標準來建立多個版本。
例如,Google Play中multi-apk支持4個不一樣的過濾器。爲每個過濾器而建立的apk要求使用多個Product Flavor維度。
假設有一個遊戲項目,有demo和付費版本,想要使用multi-apk中的ABI過濾器。因爲要兼顧3種ABI和兩個版本,因此須要生成6個apk(沒有計算多個Build Type產生的版本)。
然而,付費版本的代碼對於全部三個ABI都是同樣,所以建立簡單的6個flavor不是一個好方法。
相反的,將flavor分爲兩個維度,並自動構建全部可能的組合variant。
這個功能經過Flavor Dimensions來實現。flavor都被分配到一個特定的維度
android { ... flavorDimensions "abi", "version" productFlavors { freeapp { flavorDimension "version" ... } x86 { flavorDimension "abi" ... } } }
在android.flavorDimensions
數組中定義可能的維度,而且每一個flavor都指定一個維度。
根據已經劃分維度的flavor([freeapp, paidapp] 和 [x86, arm, mips]),和Build Type[debug, release],會建立如下variant:
android.flavorDimensions
中定義維度的順序很是重要。
每一個variant配置由多個Product Flavor對象決定:
維度的順序決定哪一個flavor的配置會覆蓋另外一個,這對資源來講很重要,高優先級flavor中的資源會替換低優先級的。flavor維度定義時高優先級在前。因此上面的例子中:
abi > version > defaultConfig
多維flavor項目也有額外的sourceset,和variant相似,可是沒有build type:
src/x86Freeapp/
src/armPaidapp/
這些sourceset容許在flavor-combination的級別進行定製。他們比基礎的flavor sourceset優先級高,可是比build type sourceset優先級低。
android { compileOptions { sourceCompatibility = "1.6" targetCompatibility = "1.6" } }
默認值是1.6。影響全部編譯java源碼的任務。
android { aaptOptions { noCompress 'foo', 'bar' ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~" } }
影響全部使用aapt的任務。
android { dexOptions { incremental false preDexLibraries = false jumboMode = false javaMaxHeapSize "2048M" } }
影響全部使用dex的任務。
基礎的Java項目有一套有限的任務共同工做來生成輸出。
classes
任務是一個編譯Java源碼的任務。很容易在build.gradle
文件的腳本中用classes
調用。這是project.tasks.classes
的縮寫。
在Android項目中,狀況就有點複雜,由於存在大量一樣的任務,他們的名字是基於Build Type 和 Product Flavor生成的。
爲了解決這個問題,android
有兩個屬性:
這三者分別返回一個ApplicationVariant
, LibraryVariant
, 和 TestVariant
對象的DomainObjectCollection。
要注意使用這些collection中的任一個都會觸發建立全部的任務。這意味着使用collection以後不該該修改配置。
DomainObjectCollection
能夠直接訪問全部對象,或者經過過濾器篩選(更方便)。
android.applicationVariants.each { variant -> .... }
全部三種variant共享下面這些屬性:
Property Name | Property Type | Description |
---|---|---|
name | String | variant的名字,必須是惟一的 |
description | String | variant的描述 |
dirName | String | Variant的子文件夾名,必須是惟一的。可能也會有多個子文件夾,例如「debug/flavor1」 |
baseName | String | variant輸出的基本名字,必須惟一 |
outputFile | File | Variant的輸出,這是一個可讀寫的屬性 |
processManifest | ProcessManifest | 處理Manifest的任務 |
aidlCompile | AidlCompile | 編譯AIDL文件的的任務 |
renderscriptCompile | RenderscriptCompile | 編譯Renderscript文件的任務 |
mergeResources | MergeResources | 合併資源文件的任務 |
mergeAssets | MergeAssets | 合併asset的任務 |
processResources | ProcessAndroidResources | 處理並編譯資源文件的任務 |
generateBuildConfig | GenerateBuildConfig | 生成BuildConfig類的任務 |
javaCompile | JavaCompile | 編譯Java源代碼的任務 |
processJavaResources | Copy | 處理Java資源文件的任務 |
assemble | DefaultTask | variant的標誌任務assemble |
ApplicationVariant
擁有如下額外屬性:
Property Name | Property Type | Description |
---|---|---|
buildType | BuildType | variant的構建類型 |
productFlavors | List | Variant的ProductFlavor。通常不爲空但容許空值 |
mergedFlavor | ProductFlavor | android.defaultConfig和variant.productFlavors的合併 |
signingConfig | SigningConfig | variant使用的SigningConfig對象 |
isSigningReady | boolean | 若是是true則代表這個variant已經具有了簽名所需的全部信息 |
testVariant | BuildVariant | 將會測試這個variant的TestVariant |
dex | Dex | 將代碼打包成dex的任務,庫工程該屬性能夠爲空 |
packageApplication | PackageApplication | 打包出最終apk的任務,庫工程該屬性能夠爲空 |
zipAlign | ZipAlign | 對apk進行對齊(zipalign)的任務,庫工程或者apk沒法簽名時,該屬性能夠爲空 |
install | DefaultTask | 安裝apk的任務,能夠爲空 |
uninstall | DefaultTask | 卸載任務 |
LibraryVariant
擁有如下額外屬性:
Property Name | Property Type | Description |
---|---|---|
buildType | BuildType | variant的構建類型 |
mergedFlavor | ProductFlavor | The defaultConfig values |
testVariant | BuildVariant | 用於測試這個variant的Variant |
packageLibrary | Zip | 打包成庫工程AAR文件的任務,非庫工程該屬性爲空 |
TestVariant
擁有如下額外屬性:
Property Name | Property Type | Description |
---|---|---|
buildType | BuildType | variant的構建類型 |
productFlavors | List | Variant的ProductFlavor。通常不爲空但容許空值 |
mergedFlavor | ProductFlavor | android.defaultConfig和variant.productFlavors的合併 |
signingConfig | SigningConfig | variant使用的SigningConfig對象 |
isSigningReady | boolean | 若是是true則代表這個variant已經具有了簽名所需的全部信息 |
testedVariant | BaseVariant | 被當前TestVariant測試的BaseVariant |
dex | Dex | 將代碼打包成dex的任務,庫工程該屬性能夠爲空 |
packageApplication | PackageApplication | 打包出最終apk的任務,庫工程該屬性能夠爲空 |
zipAlign | ZipAlign | 對apk進行對齊(zipalign)的任務,庫工程或者apk沒法簽名時,該屬性能夠爲空 |
install | DefaultTask | 安裝apk的任務,能夠爲空 |
uninstall | DefaultTask | 卸載任務 |
connectedAndroidTest | DefaultTask | 在已鏈接的設備上運行android測試的任務 |
providerAndroidTest | DefaultTask | 使用擴展API運行android測試的任務 |
API for Android specific task types.
android特有任務的API:
因爲Gradle的工做方式和Android plugin的配置方式, 每一個task類型的API是受限的。
首先,Gradle使得任務只能配置輸入輸出的路徑和一些可能使用的選項標識。所以,任務只定義一些輸入或者輸出。
其次,大多數任務的輸入都很複雜,通常都混合了sourceSet、Build Type和Product Flavor中的值。爲了保持構建文件的簡單,可讀,咱們的目標是讓開發者經過略微改動DSL對象來修改構建過程,而不是深刻到輸入文件和任務選項中去。
另外須要注意,除了ZipAlign這個任務類型,其它全部類型都要求設置私有數據來讓它們運行。這意味着不能手動建立這些任務的實例。
這些API也可能改變。大致來講,當前的API是圍繞着修改任務的輸入(可能的話)和輸出來添加額外的處理過程(必要的話)。歡迎反饋,特別是那些沒有預見到的問題。
對於Gradle任務(DefaultTask, JavaCompile, Copy, Zip),請參考Gradle文檔。
敬請期待。
對於Gradle任務(DefaultTask, JavaCompile, Copy, Zip),請參考Gradle文檔。
使用Android KitKat(buildTools v19)就可使用diamond operator,multi-catch,在switch中使用字符串,try with resource等等(jdk7中的新特性),要使用這些,須要修改你的構建文件以下:
android { compileSdkVersion 19 buildToolsVersion "19.0.0" defaultConfig { minSdkVersion 7 targetSdkVersion 19 } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } }
注意:你能夠將minSdkVersion的值設置爲19以前的版本,只是你只能使用除了try with resources以外的語言特性。若是你想要使用try with resources特性,你就須要把minSdkVersion也設置爲19。
你一樣也須要確認Gradle使用1.7或者更高版本的JDK。(Android Gradle plugin也須要0.6.1或者更高的版本)