導讀java
Gradle基於Groovy的特定領域語言(DSL)編寫的一種自動化建構工具,Groovy做爲一種高級語言由Java代碼實現,本文將對Gradle一些常見問題進行一一介紹:android
android應用程序使用開源工具Gradle構建。Gradle一種藝術API,很是容易的支持定製,而且在java世界有着普遍的應用。Android爲了實現編譯、打包等,開發者開發了Android插件爲Gradle添加了一系列的新特徵,特別是在構建Android app上的應用,包括:構建類型、多樣化、簽名配置、庫文件工程等等功能。spring
在咱們使用Android Studio工具開發Android應用的時候,當建立一個新的Android工程,默認的Gradle構建文件包括了setting.gradle
, build.gradle
和app/build.gradle
。具體位置如圖所示。api
[--> setting.gradle]緩存
include ':app'
[--> build.gradle]網絡
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0+' } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
其實原始的Gradle默認狀況下並不包含Android功能。Google爲Gradle提供了Android插件,容許用戶很容易的配置android工程編譯腳本。編譯腳本(buildscript)在編譯工程的根目錄,構建文件(build.gradle)用來告知Gradle去哪裏下載對應的插件。app
從上面列出的代碼中咱們能夠看到插件的默認下載是從jcenter
中,意味着jcenter
就是當前的目標庫。雖然jcenter
倉庫是當前默認的,可是其它的倉庫也是支持的,尤爲是mavenCenteral()
做爲maven的遠端默認倉庫。JCenter倉庫的全部內容經過一個CDN經由HTTPS鏈接傳輸,速度也是很快的。eclipse
上面代碼中的allprojects
部分表示當前的根目錄工程和所屬的子工程默認狀況下都使用jcenter()遠端倉庫用來支持java庫的依賴。maven
Gradle容許用戶定義不少任務(tasks),並插入到有向無環圖(directed acyclic graph,DAG)中,Gradle經過DAG來解析任務之間的依賴關係。在上面代碼中一個clean任務已經添加到根目錄的構建文件中。其中的type: Delete表示依賴Gradle中定製已有的Delete任務。在這種狀況下,該任務會移除在工程根目錄下的構建目錄(也就是build目錄)。ide
app做爲項目工程的module,內部須要包含build.gradle來支持module編譯,接下來來看一下app目錄下的build.gradle。
[--> app/build.gradle]
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId "com.kousenit.myandroidapp" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.3.0' }
這部分的代碼功能並不是由Gradle工具提供,是由Android插件構建系統提供,經過加入android標籤,容許android塊使用DSL(Domin Specific Language)編寫配置。
dependencies部分包含了三行。
fileTree
作依賴,表示全部在libs目錄下的以.jar爲後綴名的文件添加到編譯路徑中。src/androidTest/java
路徑下生效,用來增長測試單元(本文沒有介紹測試)。[--> app/build.gradle]
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId "com.kousenit.myandroidapp" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } }
在build.gradle文件的頂部添加Android應用程序插件。Module(模塊)編譯文件經過apply plugin: 'com.android.application'
,加載應用程序插件,從而使Gradle DSL支持android標籤。
android DSL使用模塊方式嵌入。必須指出編譯目標版本(compileSdkVersion)和編譯工具版本(buildToolsVersion)。兩個值儘可能跟進較近的版本,而非老版本,由於新版本會修復老版本工具含的一些bug。
屬性 | 解釋 |
---|---|
applicationId | 應用的包名,該值必須惟一 |
minSdkVersion | 應用支持的最小Android SDk版本 |
targetSdkVersion | 應用目標版本,Android studio會根據當前版本提示相應的警告信息 |
versionCode | 用一個整數表示當前app的版本,用以升級使用 |
versionName | 用一個字符表示當前app版本名稱,用以升級使用 |
轉到Gradle以後,minSdkVersion和buildToolsVersion屬性被指定,這兩個屬性和Android Manifest中的<uses-sdk>標籤屬性內容一致。Android Manifest中的<uses-sdk>標籤已經被取消,如若值仍然存在在Manifest中,值將被Gradle中的值覆蓋。
從命令行須要用戶提供Gradle wrapper或者安裝Gradle並直接運行。
[gradle-wrapper.properties]
#Thu Sep 22 19:09:25 CST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
其中distributionUrl屬性表示wrapper包將要下載和安裝gradle-2.14.1版本。在第一次執行結束以後,Gradle目標將被緩存在zipStorePath文件夾,在zipStoreBase目錄之下。之後每次構建將直接使用緩存的版本構建任務。
命令很是簡單:
./gradlew build
最後輸出的apk在app/build/outputs/apk目錄下。咱們也能夠執行多任務經過空格:
./gradlew lint assembleDebug
其中查看依賴樹經過:
./gradlew anDep
取消編譯任務: ./gradlew pro
若是不想使用編譯build.gradle文件,使用-b切換編譯腳本文件:
./gradlew -b app.gradle
如何在Android Studio環境下,執行編譯任務?當咱們建立Android工程後,Android Studio會爲多個工程腳本生成Gradle構建文件。IDE提供了Gradle任務列表的可視化視圖,以下圖所示:
Gradle提供了不少分類,像android, build, install和other。執行某一個任務的時候只須要雙擊具體的名稱,在Gradle窗口中。每次運行一個特殊的task,運行配置就會被建立並存儲在Run Configurations菜單下,因此再次運行的時候能夠在這裏選擇。
Android studio提供了Gradle Console輸出相應的編譯信息。
默認狀況下,Android應用包含了兩個gradle文件:一個在根目錄下,一個在應用目錄下。在應用目錄下的gradle腳本須要增長依賴:
[app/build.gradle]
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.3.0' }
每個依賴關係表示了一個配置。Android工程的依賴包含了編譯、運行、測試編譯、測試運行。完整的依賴包含三個部分:group, name, 和version信息。插件能夠增長額外的配置信息,也可以定義本身的信息。完整的信息以下:
testCompile group: 'junit', name: 'junit', version: '4.12'
簡寫爲:
testCompile 'junit:junit:4.12'
版本簡寫:
testCompile 'junit:junit:4.+'
若是你想配置相應的文件,可經過files和fileTree增長依賴:
dependencies { compile files('libs/a.jar', 'libs/b.jar') compile fileTree(dir: 'libs', include: '*.jar') }
傳遞依賴:
./gradlew androidDependencies
Gradle默認狀況下是開始網絡檢查依賴庫的,若是有特殊需求須要關閉,採用transitive
標誌關閉網絡請求:
dependencies { runtime group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.0.1', transitive: false }
將transitive
標誌改爲false會阻止依賴的下載。因此若是須要的話必須加載本身的本地。若是但願模塊是jar文件,寫法以下:
dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.4[@jar](https://my.oschina.net/u/1767170)' compile group: 'org.codehaus.groovy', name: 'groovy-all',version: '2.4.4', ext: 'jar' }
有經驗的開發者能夠很輕鬆的編輯build.gradle文件,而不須要藉助IDE的幫助。可是IDE也給出了相應的編輯視圖。
打開File->Project Structure,選擇相應的modules便可對build.gradle進行編輯。以下圖所示:
其中Dependencies選項卡中的Scope行容許用戶配置依賴庫是提供到apk中,仍是隻是編譯的時候依賴:
在Gradle的dependencies是怎麼樣精準的找到相應的依賴的呢?經過在repositories配置的,全部的dependencies都會去找到相應的依賴,才能夠正常編譯。默認倉庫爲JCenter。注意當前使用HTTPS鏈接。
repositories { mavenLocal() mavenCentral() }
一些Maven庫也能夠經過URL添加,以下例添加一個maven庫:
repositories { maven { url 'http://repo.spring.io/milestone' } }
密碼保護倉庫可使用credentials模塊來表示,經過用戶名和密碼的校驗來獲取依賴倉庫,代碼以下所示:
repositories { maven { credentials { username 'username' password 'password' } url 'http://repo.mycompany.com/maven2' } }
也能夠將用戶名和密碼值移到gradle.properties文件中。Ivy和local倉庫語法相似,參考下例:
repositories { ivy { url 'http://my.ivy.repo' } }
當使用本地文件,能夠經過flatDir語法來建立倉庫,。以下例所示:
repositories { flatDir { dirs 'libs' } }
使用flatDir是使用files或是fileTree方案的一種替代,fileTree須要指定路徑,就再也不須要指定flatDir本地文件,可是aar文件依賴的時候須要指定本地庫,使用flatDir標籤。當咱們爲應用程序構建添加不少倉庫。Gradle輪詢每個倉庫,直到解析完畢全部的依賴,找到全部依賴,不然會報出錯誤。
當你想爲工程添加外部屬性或者是硬編碼值的時候,可使用ext標籤來添加。要從編譯文件中刪除它們並放入到gradle.properties文件中,或者經過命令行使用-P標誌設置。
Gradle構建文件(build.gradle)支持屬性定義,使用ext關鍵字,使用「ext」做爲「extra」簡寫。這使得變量定義很是方便。這些屬性能夠硬編碼到build.gradle文件,以下代碼所示:
ext { AAVersion = '4.0-SNAPSHOT' // change this to your desired version } task printProperties << { println AAVersion }
使用ext是常規Groovy語法的應用,意味着類型化AAVersion爲String類型,該變量經過printProperties任務打印。在構建文件中,使用def關鍵字實現本地變量聲明,並且只有當前構建文件可使用。若是不加def關鍵字,變量能夠在工程中使用,工程及子工程都是可使用的。
def AAVersion = '4.0-SNAPSHOT' task printProperties << { println AAVersion }
對於咱們依賴的倉庫,有時候須要校驗用戶身份,就須要咱們輸入用戶名和密碼,此時也許你但願刪除在build.gradle構建文件中的實際值,考慮到Maven庫中的登陸憑證,以下所示:
repositories { maven { url 'http://repo.mycompany.com/maven2' credentials { username 'user' password 'password' } } }
這裏不但願保留真實的用戶名和密碼值在build.gradle構建文件中,添加它們到工程根目錄下的gradle.properties文件中,以下所示:
[--> gradle.properties]
login='user' pass='my_long_and_highly_complex_password'
這樣credentials部分能夠經過變量值來替代,以下:
repositories { maven { url 'http://repo.mycompany.com/maven2' credentials { username login password pass } } }
這裏能夠經過命令行設置對應是屬性值,使用-P參數:
gradle -Plogin=me -Ppassword=this_is_my_password assembleDebug
具體演示以下所示「
ext { // 檢測工程屬性是否存在 if (!project.hasProperty('user')) { user = 'user_from_build_file' } if (!project.hasProperty('pass')) { pass = 'pass_from_build_file' } } task printProperties() { doLast { // 打印屬性 println "username=$user" println "password=$pass" } }
執行printProperties
任務能夠打印相應的屬性,不須要任何外部配置,這須要在ext塊設置相應的值。打印以下:
> ./gradlew printProperties :app:printProperties username=user_from_build_file password=pass_from_build_file
增長相應的-P標誌後:
> ./gradlew -Puser=user_from_pflag -Ppass=pass_from_pflag printProperties :app:printProperties username=user_from_pflag password=pass_from_pflag
結合"extra"塊,屬性文件和命令行標誌足以知足咱們的需求。
將Eclipse ADT程序移植到Android Studio中,將其變成Gradle目錄結構,具體以下所示:
在Eclipse ADT工程中,老的目錄結構爲res, src和AndroidManifest.xml全部直接在root目錄下。導入過程當中會將其老的工程變成新的目錄結構。在構建文件build.gradle中創建dependencise依賴關係,具體log信息以下:
ECLIPSE ANDROID PROJECT IMPORT SUMMARY ====================================== Ignored Files: -------------- The following files were *not* copied into the new Gradle project; you should evaluate whether these are still needed in your project and if so manually move them: * proguard-project.txt Moved Files: ------------ Android Gradle projects use a different directory structure than ADT Eclipse projects. Here's how the projects were restructured: * AndroidManifest.xml => app/src/main/AndroidManifest.xml * assets/ => app/src/main/assets * res/ => app/src/main/res/ * src/ => app/src/main/java/ Next Steps: ----------- You can now build the project. The Gradle project needs network connectivity to download dependencies. Bugs: ----- If for some reason your project does not build, and you determine that it is due to a bug or limitation of the Eclipse to Gradle importer, please file a bug at http://b.android.com with category Component-Tools. (This import summary is for your information only, and can be deleted after import once you are satisfied with the results.)
其中ProGuard文件被推薦使用,其他的變化就是文件目錄的調整變更。頂層生成的gradle.build文件和建立一個新的工程是同樣的。
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0+' } } allprojects { repositories { jcenter() } }
App以下的構建文件build.gradle,以下代碼,若是須要額外的jar庫還須要增長dependencies模塊。
apply plugin: 'com.android.application' android { compileSdkVersion 17 buildToolsVersion "23.0.3" defaultConfig { applicationId "com.example.tips" minSdkVersion 8 targetSdkVersion 17 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } } }
最後生成的settings.gradle文件,顯示了當前app工程包含的module目錄。
include ':app'
其中AndroidManifest.xml文件沒有任何改動。
Android開發工具(ADT)的Eclipse插件,是構建Android工程主要的IDE。Gradle構建在2013引入。ADT的項目如今已經啓用,Android Studio是目前支持的IDE,但遺留項目仍然存在。ADT插件能夠生成Gradle構建文件,基於當前的目錄結構和依賴。
注意:上一節中介紹從ADT到Android Studio的import過程。export過程不在被推薦
依賴於老的目錄結構再也不被推薦,這裏介紹只是作一下簡單說明,練習中咱們可使用。Gradle提供了sourceSet映射,下面展現了若是在Gradle中對老的目錄結構進行映射。
在Eclipse ADT結構中,全部的源代碼在一個目錄中src,在工程的根目錄。資源在res文件夾總,也放在根目錄中。Android的manifest.xml文件也在根目錄下。全部的這些在新的目錄結構中都已經變化。那麼咱們如何經過gradle映射原始的目錄結構呢?
android { compileSdkVersion 18 buildToolsVersion "17.0.0" defaultConfig { minSdkVersion 10 targetSdkVersion 17 } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aild.ext.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } // Move the tests to tests/java, tests/res, etc... instrumentTest.setRoot('tests') // Move the build types to build-types/<type> // For instance, build-types/debug/java, ... // This moves them out of them default location under src/<type>/... // which would conflict with src/ being used by the main source set. // Adding new build types or product flavors should be accompanied // by a similar customization. debug.setRoot('build-types/debug') release.setRoot('build-types/release') } }
Android Studio包含了Gradle構件庫。當咱們建立一個新的android應用的時候,IDE自動爲Linux系統生成gradlew腳本,爲Window系統生成gradlew.bat腳本。這些包裝語法容許咱們不安裝任何東西直接使用gradle。然而,包裝的語法會爲咱們下載相應版本的Gradle。
當項目已經持續了一段時間,可是,Gradle按期發佈了新的版本。你也許但願更新當前工程的Gradle版本,譬如性能緣由(但願更快)或是一些新特性須要添加到工程中。實現這些,有兩種選擇:
第一種改動是在build.gradle,修改其dependencies中的classpath,gradle會自動到相應的jcenter()代碼庫中拉取當前對應版本的gradle,相應修改以下所示:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0+' } }
第二種是經過更改gradle-wrapper.properties的distributionUrl的值來更改gradle版本,以下代碼所示:
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
固然第一種方案是首選的方案。
當咱們想爲多個module設置相同的配置時候,在頂層的Gradle build文件中,使用allprojects和subprojects進程聲明。當咱們在Android Studio建立一個新的Android工程後,IDE建立兩個build.gradle,一個在頂層一個在module app中。在頂層的build.gradle文件有一個標籤叫作allprojects,以下所示:
allprojects { repositories { jcenter() } }
標籤來自Gradle DSL,所以能夠爲工程下全部gradle模塊工做,而不只僅是android工程。allprojects屬性來自Gradle API,是org.gradle.api.Project
類的一個屬性。這個屬性包含當前工程和全部子工程。還有一個屬性subprojects只容許子工程使用。
經過allprojects集合咱們能夠爲每個工程設置通用屬性,默認狀況是根目錄工程和app module。這樣咱們能夠無需重複的爲每個module設置倉庫,由於咱們能夠全局設置。
使用subprojects模塊替換方案。例如,若是咱們有多個Android庫工程,每個工程的構建腳本中都須要加入apply plugin: 'com.android.library'
。若是工程中都是Android庫工程,你能夠去掉重複的聲明,直接在頂層加入subprojects聲明,實現子工程共享屬性。
subprojects { apply plugin: 'com.android.library' }
額外考慮
當咱們查看Gradle DSL參考文檔的時候,在介紹allprojects的地方,會發現allprojects使用了org.gradle.api.Action
做爲了參數。
void allprojects(Action<? super Project> action)
方法中調用executes執行全部Action,調用subprojects. Action<T> 執行,這裏就再也不介紹了。
Android APK在發佈前都須要進行數字簽名。默認狀況下Android會爲咱們籤一個debug的數字簽名,使用本地帶的一個key。咱們也能夠經過keytool命令簽名。debug密鑰庫存儲在用戶設備中中,在咱們home文件夾中,命名爲.android。默認密鑰庫名稱爲debug.keystore,而且密鑰密碼爲android。
keytool -list -keystore debug.keystore 輸入密鑰庫口令:("android") 密鑰庫類型: JKS 密鑰庫提供方: SUN 悅德財富:https://www.yuedecaifu.com 您的密鑰庫包含 1 個條目 androiddebugkey, 2016-9-28, PrivateKeyEntry, 證書指紋 (SHA1): 6A:A8:B7:B6:A6:AA:73:BD:EE:9D:31:96:68:21:47:A3:FA:2C:23:2B
keystore類型爲JKS,表明了Java的KeyStore,使用了公私鑰機制。Java支持其餘類型JCEKS(Java Cryptography Extensions KeyStore),用來作共享密鑰,可是沒用用在Android應用上。
當咱們生成debug的APK的時候,安裝在設備和模擬器上是否須要證書呢?答案是確定的,android爲咱們提供了通用證書(keystore),使用androiddbugkey做爲序列用來給全部的debug apk提供簽名。若是一個app沒有簽名,是不能發佈的,這就要求咱們必須使用證書對其進行簽名。證書使用keytool工具生成。生成方法以下:
keytool -genkey -v -keystore myapp.keystore -alias my_alias -keyalg RSA -keysize 2048 -validity 10000
具體須要輸入內容,按要求輸入便可。生成證書以後怎樣在每次運行的時候進行簽名呢?配置以下所示:
android { // ... other sections ... signingConfigs { release { keyAlias 'my_alias' keyPassword 'password' storeFile file('/Users/kousen/keystores/myapp.keystore') storePassword 'password' } } }
你也可能不想將密碼放入到構建文件中。幸運的是,你能夠放入到gradle.properties文件中或者在命令行中設置。
在DSL文檔中,signingConfigs模塊是由signingConfig類進行實例化的同時也表示了signingConfig類實例,具體屬性參考以下:
屬性 | 解釋 |
---|---|
keyAlias | keytool中生成證書的時候的隨機值 |
keyPassword | 在簽名過程當中所須要的密鑰 |
storeFile | keystore證書在磁盤中的位置 |
storePassword | keystore證書的密碼 |
同時也須要在buildTypes的release中加入簽名過程,具體以下所示:
android { // ... other sections ... buildTypes { release { // ... other settings ... signingConfig signingConfigs.release } } }
當你想經過Android Studio配置簽名,並生成相應的簽名後的APK該如何呢?Android Studio提供了生成keystore的方法:Build → Generate Signed APK選項:
點擊「Create new…」,彈出生成keystore的信息填寫頁,填寫相應的信息便可:
若是你選擇一個已經存在的keystore,輸入相應的密鑰和隨機序列能夠直接使用該keystore,以下圖所示: