Android-Gradle(四)

當你在開發一個app,通常你會有幾個版本。大多數情況是你需要一個開發版本,用來測試app和弄清它的質量,然后還需要一個生產版本。這些版本通常有不同的設置,例如不同的URL地址。更可能的是你可能需要一個免費版和收費版本?;谏鲜銮闆r,你需要處理不同的版本:開發免費版,開發付費版本,生產免費版,生產付費版,而針對不同的版本不同的配置,這極大增加的管理難度。

Gradle有一些方便的方法來管理這些問題。我們很早之前談過debug和release版本,現在我們談到另外一個概念,不同的產品版本。構建版本和生產版本通??梢院喜?,構建版本和生產版本的合并版叫做構建變種。

這一章我們將學習構建版本,它能使得開發更有效率,并且學習如何使用它們。然后我們會討論構建版本和生產版本的不同,以及如何將其合并。我們會探討簽名機制,如何針對不同的變種簽名等。

在這一章,我們遵循如下規則:

Build types
Product flavors
Build variants
Signing configurations
構建版本
在Gradle的Android插件中,一個構建版本意味著定義一個app或者依賴庫如何被構建。每個構建版本都要特殊的一面,比如是否需要debug,application id是什么,是否不需要的資源被刪除等等。你可以定義一個構建版本通過buildTypes方法。例如:

android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile
('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
這個文件定義了該模塊是release版本,然后定義了proguard的位置。該release版本不是唯一的構建版本,默認情況下,還有個debug版本。Android studio把它視為默認構建版本。

創建自己的構建版本
當默認的構建版本不夠用的時候,創建版本也是很容易的一件事,創建構建版本你只需要在buildTypes寫入自己的版本。如下所示:

android {
buildTypes {
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
buildConfigField "String", "API_URL",
""http://staging.example.com/api""
}
}
}
我們定義了一個staging版本,該版本定義了一個新的application id,這讓其與debug和release版本的applicationID不同。假設你使用了默認的配置,那么applicationID將會是這樣的:

Debug: com.package
Release: com.package
Staging: com.package.staging
這意味著你可以在你的設備上安裝staging版本和release版本。staging版本也有自己的版本號。buildConfigField定義了一個新的URL地址。你不必事事都去創建,所以最可能的方式是去繼承已有的版本。

android {
buildTypes {
staging.initWith(buildTypes.debug)
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
debuggable = false
}
}
}
initWith()方法創建了一個新的版本的同時,復制所有存在的構建版本,類似繼承。我們也可以復寫該存在版本的所有屬性。

So
Source sets
當你創建了一個新的構建版本,Gradle也創建了新的source set。默認情況下,該文件夾不會自動為你創建,所有你需要手工創建。

app
└── src
├── debug
│ ├── java
│ │ └── com.package
│ │
│ ├── res
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
├── main
│ ├── java
│ │ └── com.package
│ │
│ ├── res
└── MainActivity.java
└── Constants.java
│ │
│ │
│ │
│ └── AndroidManifest.xml
├── staging
│ ├── java
│ │ └── com.package
├── drawable
└── layout
└── activity_main.xml
│ │
│ ├── res
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
└── release
├── java
│ └── com.package
│ └── Constants.java
└── AndroidManifest.xml

注意:當你添加一個Java類的時候,你需要知道以下過程,當你添加了CustomLogic.java到staging版本,你可以添加相同的類到debug和release版本,但是不能添加到main版本。如果你添加了,會拋出異常。

當使用不同的source sets的時候,資源文件的處理需要特殊的方式。Drawables和layout文件將會復寫在main中的重名文件,但是values文件下的資源不會。gradle將會把這些資源連同main里面的資源一起合并。

舉個例子,當你在main中創建了一個srings.xml的時候:

<resources>
<string name="app_name">TypesAndFlavors</string>
<string name="hello_world">Hello world!</string>
</resources>
當你在你的staing版本也添加了rings.xml:

<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
</resources>
然后合并的strings.xml將會是這樣的:

<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
<string name="hello_world">Hello world!</string>
</resources>
當你創建一個新的構建版本而不是staging,最終的strings.xml將會是main目錄下的strings.xml。

manifest也和value文件下的文件一樣。如果你為你的構建版本創建了一個manifest文件,那么你不必要去拷貝在main文件下的manifest文件,你需要做的是添加標簽。Android插件將會為你合并它們。

我們將在會之后的章節講到合并的更多細節。

依賴包
每一個構建版本都有自己的依賴包,gradle自動為每一個構建的版本創建不同的依賴配置。如果你想為debug版本添加一個logging框架,你可以這么做:

dependencies {

compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
}
你可以結合不同的構建版本著不同的構建配置,就像這種方式,這讓你的不同版本的不同依賴包成為可能。

product flavors
和構建版本不同,product flavors用來為一個app創建不同版本。典型的例子是,一個app有付費和免費版。product flavors極大簡化了基于相同的代碼構建不同版本的app。

如果你不確定你是否需要一個新的構建版本或者product flavors,你應該問你自己,你是否需要內部使用和外部使用的apk。如果你需要一個完全新的app去發布,和之前的版本完全隔離開,那么你需要product flavors。否則你只是需要構建版本。

創建product flavors
創建product flavors非常的容易。你可以在productFlavors中添加代碼:

android {
productFlavors {
red {
applicationId 'com.gradleforandroid.red'
versionCode 3
}
blue {
applicationId 'com.gradleforandroid.blue'
minSdkVersion 14
versionCode 4
}
}
}
product flavors和構建版本的配置不同。因為product flavors有自己的ProductFlavor類,就像defaultConfig,這意味著你的所有productFlavors都分享一樣的屬性。

Source sets
就像構建版本一樣,product Flavors也有自己的代碼文件夾。創建一個特殊的版本就像創建一個文件夾那么簡單。舉個例子,當你有的生產版本的blue flavors有一個不同的app圖標,該文件夾需要被叫做blueRelease。

多個flavors構建變體
在一些例子中,你可能需要創建一些product flavors的合并版本。舉個例子,client A和client B可能都想要一個free和paid的版本,而他們又都是基于一樣的代碼,但是有不一樣的顏色等。創建四個不同的flavors意味著有重復的配置。合并flavors最簡單的做法可能是使用flavor dimensions,就像這樣:

android {
flavorDimensions "color", "price"
productFlavors {
red {
flavorDimension "color"
}
blue {
flavorDimension "color"
}
free {
flavorDimension "price"
}
paid {
flavorDimension "price"
}
}
}
當你添加了flavor dimensions,你就需要為每個flavor添加flavorDimension,否則會提示錯誤。flavorDimensions定義了不同的dimensions,當然其順序也很重要。當你合并二個不同的flavors時,他們可能有一樣的配置和資源。例如上例:

blueFreeDebug and blueFreeRelease
bluePaidDebug and bluePaidRelease
redFreeDebug and redFreeRelease
redPaidDebug and redPaidRelease
創建構建變體
gradle讓處理構建變體變得容易。

android {
buildTypes {
debug {
buildConfigField "String", "API_URL",
""http://test.example.com/api""
}
staging.initWith(android.buildTypes.debug)
staging {
buildConfigField "String", "API_URL",
""http://staging.example.com/api""
applicationIdSuffix ".staging"
}
}
productFlavors {
red {
applicationId "com.gradleforandroid.red"
resValue "color", "flavor_color", "#ff0000"
}
blue {
applicationId "com.gradleforandroid.blue"
resValue "color", "flavor_color", "#0000ff"
}
}
}
在這個例子中,我們創建了4個變體,分別是blueDebug,blueStaging,redDebug,redStaging。每一個變體都有其不同的api url以及顏色。例如:
assembleBlue uses the blue flavor configuration and assembles both BlueRelease and BlueDebug.

assembleBlueDebug combines the flavor configuration with the build type configuration, and the flavor settings override the build type settings.

Source sets
構建變體也可以有自己的資源文件夾,舉個例子,你可以有src/blueFreeDebug/java/。
資源文件和manifest的合并
在打包app之前,Android插件會合并main中的代碼和構建的代碼。當然,依賴項目也可以提供額外的資源,它們也會被合并。你可能需要額外的Android權限針對debug變體。舉個例子,你不想在main中申明這個權限,因為這可能導致一些問題,所以你可以添加一個額外的mainfest文件在debug的文件夾中,申明額外的權限。
資源和mainfests的優先級是這樣的:



如果一個資源在main中和在flavor中定義了,那么那個在flavor中的資源有更高的優先級。這樣那個在flavor文件夾中的資源將會被打包到apk。而在依賴項目申明的資源總是擁有最低優先級。
忽略某個變體也是可行的。這樣你可以加速你的構建當使用assemble的時候,這樣你列出的tasks將不會執行那么你不需要的變體。你可以使用過濾器,在build.gradle中添加代碼如下所示:

android.variantFilter { variant ->
if(variant.buildType.name.equals('release')) {
variant.getFlavors().each() { flavor ->
if (flavor.name.equals('blue')) { variant.setIgnore(true);
}
}
}
}
在這個例子中,我們檢查下:


變體過濾器
忽略某個變體也是可行的。這樣你可以加速你的構建當使用assemble的時候,這樣你列出的tasks將不會執行那么你不需要的變體。你可以使用過濾器,在build.gradle中添加代碼如下所示:
android.variantFilter { variant -> if(variant.buildType.name.equals('release')) { variant.getFlavors().each() { flavor -> if (flavor.name.equals('blue')) { variant.setIgnore(true); } } }}

在這個例子中,我們檢查下:



你可以看到blueFreeRelease和bluePaidRelease被排除在外,如果你運行gradlew tasks,你會發現所有的關于上述變體的tasks不再存在。
簽名配置
在你發布你的應用之前,你需要為你的app私鑰簽名。如果你有付費版和免費版,你需要有不同的key去簽名不同的變體。這就是配置簽名的好處。配置簽名可以這樣定義:

android {
signingConfigs {
staging.initWith(signingConfigs.debug)
release {
storeFile file("release.keystore")
storePassword"secretpassword"
keyAlias "gradleforandroid"
keyPassword "secretpassword"
}
}
}
在這個例子中,我們創建了2個不同的簽名配置。debug配置是as默認的,其使用了公共的keystore和password,所以沒有必要為debug版本創建簽名配置了。staging配置使用了initWith()方法,其會復制其他的簽名配置。這意味著staging和debug的key是一樣的。

release配置使用了storeFile,定義了key alias和密碼。當然這不是一個好的選擇,你需要在 Gradle properties文件中配置。

當你定義了簽名配置后,你需要應用它們。構建版本都有一個屬性叫做signingConfig,你可以這么干:

android {
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
上例使用了buildTypes,但是你可能需要對每個版本生成不同的驗證,你可以這么定義:

android {
productFlavors {
blue {
signingConfig signingConfigs.release
}
}
}
當然,你在flavor中定義這些,最好會被重寫,所以最好的做法是:

android {
buildTypes {
release {
productFlavors.red.signingConfig signingConfigs.red
productFlavors.blue.signingConfig signingConfigs.blue
}
}
}

總結
在這一章,我們討論了構建版本和生產版本,以及如何結合它們。這將會是非常有用的工具,當你需要不同的url以及不同的keys,而你們有相同的代碼和資源文件,但是有不同的類型以及版本,構建版本和生產版本將會讓你的生活更美好。
我們也談論了簽名配置以及如何使用他們。
下一章,你將會學習到多模塊構建,因為當你想把你的代碼分成一個依賴包或者依賴項目的時候,或者你想把Android wear模塊放在你的應用的時候,這將非常重要。
原文:https://segmentfault.com/a/1190000004241503
關注微信公眾號獲得更多內容:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 當你在開發一個app,通常你會有幾個版本。大多數情況是你需要一個開發版本,用來測試app和弄清它的質量,然后還需要...
    justCode_閱讀 444評論 0 2
  • 開發應用時, 通常會有幾個不同的版本。最常見的是有一個測試用的臨時版本和一個生產版本。這些版本通常有不同的設置,比...
    sollian閱讀 2,402評論 0 2
  • 第四篇( 構建變體 ) 當你在開發一個app,通常你會有幾個版本。大多數情況是你需要一個開發版本,用來測試app和...
    一劍飛鴻閱讀 688評論 0 0
  • 轉載注明出處:http://www.lxweimin.com/p/5255b100930e 0. 前言 完全由個人翻...
    王三的貓阿德閱讀 2,537評論 0 4
  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項,請點擊這里進行查閱:DSL參考 1.1新構建系統...
    Chuckiefan閱讀 12,157評論 8 72