Android官方技術文件翻譯——Gradle 外掛使用者指南(1-3)
阿新 • • 發佈:2018-12-23
不知道是什麼網路問題,上午一直髮不了部落格,其他頁面基本正常,就是在寫部落格這裡,每次開啟都是響應超時。剛才用了VPN,順便試了一下,居然可以編輯。想是CDN之類的問題吧。
這次翻譯的是Gradle 外掛使用者指南,也就是Gradle上的Android外掛的官方文件。文件很長,加上最近激情不夠,翻譯得有些慢。到昨天為止,才譯到第四章。今天先發前三章。
本文譯自Android官方技術文件《Gradle Plugin User Guide》,原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide。
翻譯不易,轉載請註明CSDN部落格上的出處:
http://blog.csdn.net/maosidiaoxian/article/details/41944325
翻譯工作耗時費神,如果你覺得本文翻譯得還OK,請點一下“頂”,我在精神上會倍受鼓勵的,謝謝。翻譯如有錯訛,敬請指正。
Gradle 外掛使用者指南
簡介
本文件是 Gradle 外掛 0.9 版本的文件。在 1.0 之前,我們所介紹的早期版本可能由於不相容問題會有所不同。新構建系統的目標
新的構建系統的目標是:- 可以很容易地重用程式碼和資源
- 可以很容易地建立應用程式的幾個變種,無論是多APK分發還是不同定製版的應用程式
- 可以很容易地配置、 擴充套件和自定義構建過程
- 好的 IDE 整合
為什麼是 Gradle ?
Gradle 是一個先進的構建系統和構建工具,它允許通過外掛建立自定義的構建邏輯。基於Gradle的以下特點,我們選擇了它:
- 域特定語言 (DSL) 來描述和處理構建邏輯
- 構建檔案基於 Groovy ,並允許通過 DSL來混合宣告性元素,以及使用程式碼來處理 DSL 元素以提供自定義邏輯。
- 基於 Maven 和 Ivy 的內建依賴管理。
- 非常靈活。允許使用最佳實現,但並不強制自己的實現方式。
- 外掛可以提供自己的 DSL 和API供構建檔案使用。
- 良好的Tooling API 供 IDE 整合
要求
- Gradle 版本需要 1.10,1.11或 1.12。外掛版本需要 0.11.1
- SDK Build Tools版本要求為 19.0.0。某些功能可能需要更高版本。
基本專案
Gradle 專案在專案的根資料夾裡的build.gradle檔案中描述它的構建邏輯。簡單的構建檔案
最簡單的 純Java專案的build.gradle如下所示:apply plugin: 'java'
這裡配置使用了Gradle內建的 Java 外掛。該外掛提供用於構建並測試 Java 應用程式所需要的東西。
最簡單的 Android 專案的 build.gradle 則是以下內容:
buildscript { repositories { mavenCentral()
} dependencies { classpath 'com.android.tools.build:gradle:0.11.1' } } apply plugin: 'android' android { compileSdkVersion 19
buildToolsVersion "19.0.0"
}在這個 Android 構建檔案中,有3個主要部分:
buildscript { ... }配置了驅動構建的程式碼。
在上面的這種情況中,它聲明瞭使用 Maven 中央庫,並且對一個Maven 檔案有一個類路徑依賴。這個檔案是包含 Gradle Android 外掛的 0.11.1版本的庫
注: 這隻會影響執行構建的程式碼,不會影響專案的原始碼。專案本身需要定義它自己的倉庫和依賴關係。稍後會提及這部分。
然後,和先前的提到的 Java 外掛一樣,這裡配置使用了 android外掛。
最後, android { ... }配置了用於 android 構建的所有引數。這是Android DSL的入口。
預設情況下,只需要配置編譯目標,以及build-tools的版本。它通過compileSdkVersion和buildtoolsVersion屬性來完成。 編譯目標相當於舊的構建系統中project.properties 檔案內的target屬性。這個新的屬性可以設定為一個 int 值 (表示api 級別),或者是和以前的target的值一樣,設定為字串。
重要提示:你應該只配置使用這個android外掛。如果同時配置使用了java外掛也會導致構建錯誤。
注:您還需要一個local.properties檔案,通過sdk.dir屬性來設定 SDK 的位置,並且所設定的這個SDK要求存在。
或者,您也可以設定一個ANDROID_HOME環境變數。這兩種方法之間沒什麼差別,你喜歡,你選擇。
專案結構
上述的基本構建檔案要求有一個預設的資料夾結構。Gradle 遵循約定大於配置的概念,在可能的情況下提供了合理的預設選項值。基本專案開始於兩個名為“source sets”的元件。即主原始碼和測試程式碼。它們分別在:
- src/main/
- src/androidTest/
對於 Java 和 Android 外掛,Java 原始碼和 Java 資源的位置如下:
- java/
- resources/
- AndroidManifest.xml
- res/
- assets/
- aidl/
- rs/
- jni/
配置專案結構
When the default project structure isn’t adequate, it is possible to configure it. 根據 Gradle 文件,為一個Java 專案重新配置 sourceSets可以通過如下方法實現:sourceSets { main { java { srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
} }
注: srcDir實際上會將給定的資料夾新增到現有的原始檔夾列表中 (這在Gradle 文件中沒有提及,但這是實際的行為)。
如果要替換預設的原始檔夾,您就要使用傳入一個路徑陣列的srcDirs來代替。以下是使用涉及的物件的另一種不同的方法:
sourceSets { main.java.srcDirs = ['src/java'] main.resources.srcDirs = ['src/resources'] }
欲瞭解更多資訊,請參閱 Gradle 文件中關於 Java 外掛的內容,見這裡。
Android 外掛使用類似的語法,但因為它使用它自己的sourceSets,所以在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')}}
注意: 因為舊的結構把所有原始檔 (java、 aidl、 renderscript和 java 資源) 都放在相同的資料夾中,我們需要重新對映sourceSet的所有這些新元件到相同的src資料夾中。
注意: setRoot()會將整個sourceSet (和它的子資料夾) 移到一個新的資料夾中。這將移動src/androidTest/*到tests/*
下。這是 Android 專用的,不適用於 Java sourceSets。
這也是一個“遷移”的例子。
構建任務
常規任務
在構建檔案中配置使用一個外掛,將自動建立一系列要執行的構建任務。Java 外掛和 Android 外掛都是。 約定的任務如下:- assemble
組裝專案的輸出的任務 - check
執行所有檢查的任務。 - build
這個任務將執行assemble和check。 - clean
這個任務將清理專案的輸出
。
例如,配置使用findbugs外掛將建立一個新的任務和使check任務依賴於它,使得每當呼叫check任務時都會呼叫到它。
您可以從命令列中執行下面的命令來獲取更高級別的任務:
gradle tasks下面的命令可以得到一個完整的任務列表,並且看到任務執行之間的依賴關係:
gradle tasks --all注: Gradle 會自動監視一個任務所宣告的輸入和輸出。
在沒有變化的情況下,執行兩次build會使 Gradle 報告所有任務為UP-TO-DATE狀態,這個狀態意味著沒有任何事情需要執行。這允許任務正確地相互依賴而無需不必要的構建操作。
Java 專案任務
Java 外掛主要建立兩個任務,它們是主要錨記任務的依賴任務:- assemble
- jar
這個任務將建立輸出。
- jar
- check
- test
這個任務將執行測試。
- test
testClasses任務用於編譯測試,但它很少會被呼叫,因為test任務依賴於它 (以及classes任務)。
一般情況下,你將可能永遠只調用assemble或check,而無視其他任務。
在這裡,你可以看到Java 外掛的所有任務和對它們的描述。
Android 任務
Android 的外掛使用相同的約定配置以相容其他外掛,並添加了另外的錨記任務:- assemble
組裝專案的輸出的任務 - check
執行所有檢查的任務。 - connectedCheck
執行需要一個已連線的裝置或模擬器的檢查。它們將在所有已連線的裝置上並行執行。 - deviceCheck
使用 API 連線到遠端裝置執行檢查。這一個是在 CI 伺服器上使用的。 - build
這項任務將執行assemble 和 check - clean
這個任務將清理專案的輸出
注意到,build任務不依賴於deviceCheck或connectedCheck。
Android 專案具有至少兩個輸出: debug版本的APK 和release版本的 APK。這裡的每一個輸出都有自己的錨記任務,以便單獨構建它們:
- assemble
- assembleDebug
- assembleRelease
提示:在命令列上,Gradle 支援任務名稱的駝峰命名法的簡寫。例如:
gradle aR相當於輸入
gradle assembleRelease只要沒有其他任務匹配 “aR”
check錨記任務有它們自己的依賴項:
- check
- lint
- connectedCheck
- connectedAndroidTest
- connectedUiAutomatorTest (暫未實現)
- deviceCheck
- 這個任務依賴於當其他外掛實現了測試擴充套件點時建立的任務。
基本的構建定製
Android 外掛提供了大量的 DSL,以通過構建系統直接地自定義大部分事情。清單條目
通過 DSL 可以配置以下清單條目:- minSdkVersion
- targetSdkVersion
- versionCode
- versionName
- 用於測試應用程式的包名
- Instrumentation test runner
android { compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig { versionCode 12
versionName "2.0"
minSdkVersion 16
targetSdkVersion 16
} }
在android元素的內部的defaultConfig元素是定義所有這些配置的地方。 以前版本的 Android 外掛使用packageName來配置清單的“packageName”屬性。 從 0.11.0開始,你應該在 build.gradle 中使用 applicationId 來配置清單中的“packageName”條目。 它消除了應用程式的包名(指它的 ID)和java 包名之間的所引起的混亂。
在構建檔案中描述它的強大之處是它可以是動態的。
例如,可以從檔案中的某處或使用一些自定義的邏輯讀取版本資訊:
def computeVersionName() { ... } android { compileSdkVersion 19 buildToolsVersion "19.0.0" defaultConfig { versionCode 12 versionName computeVersionName()注意: 不要使用在作用域內可能與已存在的getter函式有衝突的函式名稱。例如 defaultConfig { ...} 例項呼叫 getVersionName() 時將自動使用 defaultConfig.getVersionName() 的 getter 方法,而不是自定義的方法。
minSdkVersion 16
targetSdkVersion 16
} }
如果一個屬性未通過 DSL 來設定,它將使用預設值。下表描述了對於未設定的屬性的處理方式。
屬性名稱 | DSL 物件中的預設值 | 預設值 |
versionCode | -1 | 如果在清單中存在,則使用清單中的值 |
versionName | null | 如果在清單中存在,則使用清單中的值 |
minSdkVersion | -1 | 如果在清單中存在,則使用清單中的值 |
targetSdkVersion | -1 | 如果在清單中存在,則使用清單中的值 |
applicationId | null | 如果在清單中存在,則使用清單中的值 |
testApplicationId | null | applicationId + “.test” |
testInstrumentationRunner | null | android.test.InstrumentationTestRunner |
signingConfig | null | null |
proguardFile | N/A (只設置) | N/A (只設置) |
proguardFiles | N/A (只設置) | N/A (只設置) |
第二列的值是很重要的,如果您在構建指令碼中使用自定義邏輯查詢這些屬性的話。例如,您可以編寫:
if (android.defaultConfig.testInstrumentationRunner == null) { // assign a better default... }如果值仍然為null,那麼在構建的時候它將會被設為第三列中的實際預設值,但是由於 DSL 元素不包含此預設值,因此您無法查詢它。
這是為了防止解析應用程式的清單,除非真的很需要。
構建型別
預設情況下,Android 外掛自動將專案設定為生成應用程式的的debug和release版本。 這兩個版本的不同,大多是圍繞在除錯一個安全的(非開發版的)裝置的能力,以及 apk 怎麼簽名。除錯版本使用自動建立的金鑰/證書籤名,並且金鑰/證書的使用者名稱/密碼是已知的(以防止構建過程中需要相關的資訊)的。release版本在構建的時候不會進行簽名,需要在之後進行簽名。
這個配置是通過一個叫BuildType的物件來完成的。預設情況下,2 個例項會被建立,分別是debug版和release版。
Android 外掛允許自定義這兩個例項,以及建立其他的構建型別。它通過buildTypes DSL 容器來實現:
android { buildTypes { debug { applicationIdSuffix ".debug"
} jnidebug.initWith(buildTypes.debug) jnidebug { packageNameSuffix ".jnidebug" jniDebuggable true } } }
上面的程式碼段可實現以下操作:
- 配置預設的Debug Build Type:
- 設定包名為<app appliationId>.debug,以便能夠在相同的裝置上安裝debug和release兩個版本的apk
- 建立一個叫jnidebug的新的BuildType物件 ,並將其配置為debug生成型別的一個副本。
- 通過啟用 JNI 元件的debug構建,並新增不同的包字尾,繼續配置jnidebug。
以下是可能用到的屬性和它們的預設值:
屬性名稱 | 用於 debug的預設值 | 用於 release/其他 的預設值 |
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 (只設置) | N/A (只設置) |
proguardFiles | N/A (只設置) | N/A (只設置) |
除了這些屬性,Build Types還會影響到構建的程式碼和資源。
對每個Build Type都會建立一個自動匹配的sourceSet,預設位置為
src/<buildtypename>/這意味著Build Type的名字不能為main或者是androidTest (這是外掛所強制的),並且它們之間必須是唯一的。
與任何其他source set一樣,生成型別的source set的位置也是可以重新設定的:
android { sourceSets.jnidebug.setRoot('foo/jnidebug') }此外,對於每個Build Type,會建立一個新的assemble<BuildTypeName>任務。
已經提到過的assembleDebug和assembleRelease這兩個任務,這裡也會講一下它們是怎麼來的。當debug和releaseBuild Types被預建立的時候,他們的任務也會被自動建立。然後,
上面的build.gradle片段也會生成一個assembleJnidebug任務,並且assemble將會依賴於它,就像它依賴於assembleDebug和assembleRelease任務一樣。
提示: 請記住您可以輸入gradle aJ來執行assembleJnidebug任務。
可能會用到的情況:
- release模式下不需要,但debug模式下需要的許可權
- 自定義的debug實現
- 為除錯模式使用不同的資源 (例如某個資源的值與簽名證書相繫結時)。
- manifest將被合併到應用程式的manifest中
- 程式碼只是作為另一個原始檔夾來起作用
- 資源將覆蓋main裡面的資源,並替換已經存在的值。
簽名配置
對應用程式進行簽名,要求如下:- 一個 keystore
- 一個 keystore 的密碼
- 一個 key 的別名
- 一個 key 的密碼
- 儲存型別
預設情況下,有一個debug的配置,配置使用了一個debug keystore。這個keystore使用了一個已知的key和一個已知的密碼。
這個debug keystore 位於$HOME/.android/debug.keystore,並且會在不存在時被建立。debug Build Type被設定為自動使用此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的位置修改為在專案的根位置下。這會自動影響到任何設定為使用它的Build Types,在這裡,影響到的是debug Build Type。
程式碼的程式碼還建立了一個新的Signing Config和使用新配置的新的Build Type 。
注:只有位於預設位置下的debug keystores才會被自動建立。如果debug keystore的位置被更改了,它將不會在需要時自動建立。建立一個使用一個不同的名稱SigningConfig,但使用了預設的debug keystore的路徑,它也會被自動建立。換句話說,會不會被自動建立與keystore的路徑有關,而與配置名稱無關。
注: keystore的路徑通常使用專案根目錄的相對路徑,但也可以是使用絕對路徑,儘管這不推薦 (除了自動建立的debug keystore)。 注意: 如果您將這些檔案加入版本控制,您可能不希望這些檔案中有你的密碼。下面的 Stack Overflow 連結顯示瞭如何從控制檯或環境變數中讀取值的方法。 我們會在以後更新本指南補充更詳細的資訊。
執行ProGuard
ProGuard 是通過 Gradle plugin for ProGuard version 4.10來進行支援的。ProGuard 外掛會被自動配置使用,並且如果Build Type通過minifyEnabled屬性配置為執行ProGuard,對應的任務將被自動建立。 android {buildTypes {
release {
minifyEnabled true
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
productFlavors { flavor1 {
} flavor2 { proguardFile 'some-other-rules.txt'
} }
} 變種使用他們的構建型別中所宣告的規則檔案,product flavors(定製版本)則使用flavor中宣告的規則檔案。 這裡有 2 個預設的規則檔案
- proguard-android.txt
- proguard-android-optimize.txt