Gradle for Android ( 構建變體 )

  有時候咱們一個app須要有不一樣的版本,不一樣的版本又會使用不一樣的配置,咱們可使用gradle進行管理。
  
  Build types
  
  Product flavors
  
  Build variants
  
  Signing configurations
  
  1、構建版本Build types:
  
  常見的構建版本有debug與release。
  
  複製代碼
  
  buildTypes {
  
  release {
  
  minifyEnabled false
  
  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  
  }
  
  }
  
  複製代碼
  
  自定義構建版本:
  
  複製代碼
  
  custom {
  
  applicationIdSuffix ".custom"
  
  versionNameSuffix ".custom"
  
  minifyEnabled false
  
  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  
  signingConfig signingConfigs.readerDaquanConfig
  
  }
  
  複製代碼
  
  除了debug構建版本不須要簽名外,其它的都是須要配置簽名的,否則沒法運行在手機上,該版本定義了新的applicationId與版本號。不一樣構建版本的applicationId以下:
  
  Debug: com.package
  
  Release: com.package
  
  Staging: com.package.staging
  
  也能夠採用繼承的方式:
  
  複製代碼
  
  custom.initWith(buildTypes.debug)
  
  custom {
  
  applicationIdSuffix ".custom"
  
  versionNameSuffix ".custom"
  
  minifyEnabled false
  
  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  
  signingConfig signingConfigs.readerDaquanConfig
  
  }
  
  複製代碼
  
  custom繼承debug構建版本的配置,custom中的配置會覆蓋debug的配置。
  
  在BuildConfig中添加變量
  
  複製代碼
  
  custom {
  
  applicationIdSuffix ".custom"
  
  versionNameSuffix ".custom"
  
  buildConfigField("String", "name","\"custom app\"")
  
  buildConfigField("int", "id", "0")
  
  minifyEnabled false
  
  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  
  signingConfig signingConfigs.readerDaquanConfig
  
  }
  
  複製代碼
  
  以後咱們能夠看到:
  
  注意若是要添加的是String,那麼雙一號裏面須要再一個雙引號標識字符串"\"custom app\"",斜杆是對裏面雙引號進行轉義。
  
  Source sets
  
  當建立了一個新的build type以後,Gradle也會建立一個新的source set。默認的source set目錄會放在相同的Build Type的目錄下。當你建立一個新的build type時,該目錄不會自動建立,你必須在你使用代碼與資源前本身爲每個build type建立source set目錄。
  
  三種buildType的目錄結構以下:
  
  複製代碼
  
  app
  
  └── src
  
  ├── debug
  
  │ ├── java
  
  │ │   └── com.package
  
  │ ├── res
  
  │ │ └── layout
  
  │ │       └── activity_main.xml
  
  │ └── AndroidManifest.xml
  
  ├── main
  
  │ ├── java
  
  │ │   └── com.package
  
  │ ├── res
  
  └── MainActivity.www.rmutk.net java
  
  └── Constants.java
  
  │ └── AndroidManifest.xml
  
  ├── custom
  
  │ ├── java
  
  │ │   └── com.package
  
  ├── drawable
  
  └── layout
  
  └── activity_main.xml
  
  │ ├── res
  
  │ │ └── layout
  
  │ │       └── activity_main.xml
  
  │ └── AndroidManifest.xml
  
  └── release
  
  ├── java
  
  │   └── com.package
  
  │       └── Constants.java
  
  └── AndroidManifest.xml
  
  複製代碼
  
  假如咱們本身創建custom的source set
  
  咱們使用不一樣的構建版本便會使用不一樣的source set。當使用不一樣的source sets的時候,資源文件的處理須要特殊的方式。Drawables和layout文件將會複寫在main中的重名文件,可是values文件下的資源不會。gradle將會把這些資源連同main裏面的資源一塊兒合併。(若是出現資源重複異常,請clean一下工程)
  
  例如,在main中的string.xml爲:
  
  <resources>
  
  <string name="app_name">BuildTypeProject</string>
  
  <string name="hello_name">BuildTypeHello</string>
  
  </resources>
  
  在custom版本中爲:
  
  <resources>
  
  <string name="app_name"www.xcdeyiju.com>BuildTypeCustomProject</string>
  
  </resources>
  
  當咱們構建custom版本的時會合併爲:
  
  <resources>
  
  <string name="app_name">BuildTypeCustomProject</string>
  
  <string name="hello_name">BuildTypeHello</string>
  
  </resources>
  
  當你建立一個新的構建版本而不是custom,最終的strings.xml將會是main目錄下的strings.xml。
  
  manifest也和value文件下的文件同樣。若是你爲你的構建版本建立了一個manifest文件,那麼你沒必要要去拷貝在main文件下的manifest文件,你須要作的是添加標籤。Android插件將會爲你合併它們。
  
  可是須要注意,當咱們添加.java文件到custom版本中,你能夠添加相同的類到debug和release版本,可是不能添加到main版本。若是你添加了,會拋出異常。這時候咱們若是構建custom版本,那麼便會使用custom對應source set中的.java文件。
  
  依賴包
  
  每個構建版本都有本身的依賴包,gradle自動爲每個構建的版本建立不一樣的依賴配置。若是你想爲debug版本添加一個logging框架,你能夠這麼作:
  
  複製代碼
  
  dependencies {
  
  compile fileTree(dir: 'libs', include: ['www.osgjyl.com*.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。
  
  建立product flavors
  
  複製代碼
  
  android {
  
  productFlavors {
  
  vivo {
  
  applicationId "vivo"
  
  versionCode 1
  
  minSdkVersion 15
  
  }
  
  oppo {
  
  applicationId "oppo"
  
  versionCode 2
  
  minSdkVersion 15
  
  }
  
  }
  
  }
  
  複製代碼
  
  這時候AS 3.0以上會報錯ERROR: All flavors must now belong to a named flavor dimension
  
  沒有給它們設置一個風味維度,咱們能夠加上
  
  flavorDimensions "default"
  
  複製代碼
  
  flavorDimensions "default"
  
  android {
  
  productFlavors {
  
  vivo {
  
  applicationId www.oushengguoj.com "vivo"
  
  versionCode 1
  
  minSdkVersion 15
  
  }
  
  oppo {
  
  applicationId "oppo"
  
  versionCode 2
  
  minSdkVersion 15
  
  }
  
  }
  
  }
  
  複製代碼
  
  給這些產品版本默認一個風味維度,具體有何做用,等會會講。
  
  這時候咱們會在左下角的窗口看到這麼多個變體:
  
  若是找不到該窗口,能夠在這裏打開:
  
  因爲咱們以前在custom構建版本上設置了applicationIdSuffix ".custom",因此,當咱們運行oppoCustom版本的時候,applicationId爲oppo.custom
  
  Source Set
  
  product Flavors也有本身的代碼文件夾。建立一個特殊的版本就像建立一個文件夾那麼簡單。以下圖所示:
  
  可是值得注意的是,咱們沒法再vivo文件夾裏相同的包中添加構建版本已經有的.java文件,添加了會報異常。而對於資源文件,咱們能夠添加構建版本里面有的文件,可是這個產品版本所對應的目錄的優先級低於Build type,也就是說,當Custom目錄有一張圖片,vivo目錄也有一張圖片,那麼當咱們運行打包vivoCustom版本的時候,使用的是custom裏面的圖片。除非咱們創建的文件夾是vivoCustom,那麼它的優先級便會是最高的。
  
  Multiflavor variants
  
  在某些狀況下,你可能但願建立一些聯合的Product Flavors,這個時候便要使用到咱們剛剛所說的flavorDimensions 了。
  
  設想一下,假如咱們須要打包兩個渠道的app:vivo和oppo,而這兩個渠道的app各自有付費版與免費版,那麼咱們就須要用到多維度了。
  
  首先定義兩個維度:渠道channel,付費與免費:money
  
  flavorDimensions "channel","money"
  
  複製代碼
  
  flavorDimensions www.xgjrfwsc.cn "channel","money"
  
  android {
  
  productFlavors {
  
  vivo {
  
  dimension "channel"
  
  applicationId "vivo"
  
  versionCode 1
  
  minSdkVersion 15
  
  }
  
  oppo {
  
  dimension "channel"
  
  applicationId "oppo"
  
  versionCode 2
  
  minSdkVersion 15
  
  }
  
  free {
  
  dimension "money"
  
  }
  
  vip {
  
  dimension www.yunyouuyl.com"money"
  
  }
  
  }
  
  }
  
  複製代碼
  
  當你添加了flavor dimensions,你就須要爲每一個flavor添加dimension,不然會提示錯誤。
  
  以後咱們能夠看到這麼多個變體:
  
  而咱們定義多個維度的順序是很重要的,由於當你在各個維度各自定義了同一個常量的值,好比:buildConfigField("String", "name","\"custom app\""),老是以第一維度的爲準。
  
  Build variants
  
  構建變體
  
  構建變體是構建版本和生產版本的結合體。當你建立了一個構建版本或者生產版本,一樣的,新的變體也會被建立。
  
  像咱們上圖便有這麼多的變體:
  
  咱們能夠在這個窗口進行切換,而後運行不一樣的變體。
  
  tasks
  
  Android Plugin會爲每個配置的Build Variant建立Tasks。一個新的Android App擁有Debug和Release兩種Build Types,因此默認的就會有兩個Task,一個是assembleDebug一個是assembleRelease來構建不一樣的APK。當添加一個新的Build Type的時候,一個新的Task也就會被建立,一旦你開始添加Flavors,一整套Tasks就會被建立,由於每個BuildType的Tasks都會爲每一個Product Flavor聯合。
  
  Source sets
  
  構建變體也能夠有本身的資源文件夾,舉個例子,你能夠有src/vivoVipCustom/java/。原理與上面的相似
  
  Resource and mainfest merging
  
  Android Plugin須要在打包前對Main的SourceSet以及BuildType的SourceSet進行一次Merge。並且Library工程也會提供額外的資源,它們也會被Merge,例如Manifest.xml等等。也會在其中聲明一些權限等。
  
  Resource和Manifest.xml的優先級順序以下:
  
  若是一個資源在main中和在flavor中定義了,那麼那個在flavor中的資源有更高的優先級。這樣那個在flavor文件夾中的資源將會被打包到apk。而在依賴項目申明的資源老是擁有最低優先級。
  
  固然,若是你創建的目錄是變體的目錄入:vivoVipCustom,那麼它的優先級天然是高於Build type
  
  建立構建變體
  
  關於如何構建變量,上面已經說了,再也不重複。
  
  複製代碼
  
  flavorDimensions www.yuchengyuLe.com"channel","money"
  
  android {
  
  productFlavors {
  
  vivo {
  
  dimension "channel"
  
  applicationId "vivo"
  
  versionCode 1
  
  minSdkVersion 15
  
  }
  
  oppo {
  
  dimension "channel"
  
  applicationId "oppo"
  
  versionCode 2
  
  minSdkVersion 15
  
  }
  
  free {
  
  dimension "money"
  
  resValue "color", "colorfree", "#ff8888"
  
  }
  
  vip {
  
  dimension "money"
  
  resValue "color", "colorfree", "#ff0000"
  
  }
  
  }
  
  }
  
  複製代碼
  
  resValue "color", "colorfree", "#ff8888"表示添加顏色名爲colorfree的顏色
  
  變體過濾器
  
  忽略某個變體也是可行的。這樣你能夠加速你的構建當使用assemble的時候,這樣你列出的tasks將不會執行那麼你不須要的變體。你可使用過濾器,在build.gradle中添加代碼以下所示:
  
  複製代碼
  
  android.variantFilter { variant ->
  
  if(variant.buildType.name.equals('release')) {
  
  variant.getFlavors().each() { flavor ->
  
  if (flavor.name.equals('vivo')) { variant.setIgnore(true);
  
  }
  
  }
  
  }
  
  }
  
  複製代碼
  
  發現相關的變體不見了:
  
  Signing Configurations
  
  在你發佈你的應用以前,你須要爲你的app私鑰簽名。若是你有付費版和免費版,你須要有不一樣的key去簽名不一樣的變體。這就是配置簽名的好處。配置簽名能夠這樣定義:
  
  複製代碼
  
  android {
  
  signingConfigs {
  
  custom.initWith(signingConfigs.debug)
  
  release {
  
  storeFile file("release.keystore")
  
  storePassword"secretpassword"
  
  keyAlias "gradleforandroid"
  
  keyPassword "secretpassword"
  
  }
  
  }
  
  }
  
  複製代碼
  
  在這個例子中,咱們建立了2個不一樣的簽名配置。debug配置是as默認的,其使用了公共的keystore和password,因此沒有必要爲debug版本建立簽名配置了。custom配置使用了initWith()方法,其會複製其餘的簽名配置。這意味着custom和debug的key是同樣的。
  
  release配置使用了storeFile,定義了key alias和密碼。固然這不是一個好的選擇,你須要在 Gradle properties文件中配置。
  
  當你定義了簽名配置後,你須要應用它們。構建版本都有一個屬性叫作signingConfig,你能夠這麼幹:
  
  複製代碼
  
  android {
  
  buildTypes {
  
  release {
  
  signingConfig signingConfigs.release
  
  }
  
  }
  
  }
  
  複製代碼
  
  上例使用了buildTypes,可是你可能須要對每一個版本生成不一樣的驗證,你能夠這麼定義:
  
  複製代碼
  
  android {
  
  productFlavors {
  
  vivo{
  
  signingConfig signingConfigs.release
  
  }
  
  }
  
  }
  
  複製代碼
  
  當簽名一個Flavor版本的時候,你須要重寫BuildType中的簽名配置。當須要使用相同的BuildType不一樣版本的Flavors的簽名時,能夠經過下述方式:
  
  複製代碼
  
  android {
  
  buildTypes {
  
  release {
  
  productFlavors.vivo.signingConfig signingConfigs.vivo
  
  productFlavors.oppo.signingConfig signingConfigs.oppo
  
  }
  
  }
  
  }
  
  複製代碼
  
  上面這個例子展現瞭如何在vivo和oppo的Release版本使用不一樣的簽名,可是卻不影響Debug和Custom的BuildType。java

相關文章
相關標籤/搜索