flavorDimensions和productFlavors——安卓gradle

目錄
1、前言
2、flavorDimensions 的意義
3、productFlavors的意義
4、productFlavor
5、寫在最後
html

1、前言

有了前兩篇博客的鋪墊,咱們能夠來分享下另外兩個參數了 flavorDimensionsproductFlavors,而這兩個參數成對出現,能夠作一些差分化定義java

前兩篇博客爲:
一、defaultConfig——安卓gradle
二、buildTypes——安卓gradle
android

須要事先說明的是,接下來所說的 「意義」 並不是官方文檔翻譯,而是結合了小盆友本身的理解,會比較口語化。git

2、flavorDimensions 的意義

flavorDimensions 從單詞字面理解知道是 「風味維度」,是須要結合 「產品風味(即productFlavors)」 來一塊兒使用的。程序員

flavorDimensions 的使用會定義出維度,供接下來的 productFlavors 使用。咱們舉個例子github

android {
	// 省略其餘參數
	
	flavorDimensions('abi', 'version')
}
複製代碼

使用上面代碼,則會定義出兩個維度:version 和 abi。一個參數一個維度,咱們把它形象化,就能夠當作下面這樣一張圖。而他有什麼做用,咱們看下一小節。 後端

若是三個參數就能夠當作一個三維的空間座標系,這裏的座標系只是一個形象化的體現。bash

3、productFlavors的意義

productFlavors 從字面瞭解是「產品風味」。他須要和一個風味維度對接,不然會報錯。微信

接着咱們上面的例子,使用 productFlavors 定義維度上的風味,使用 dimension 關聯。架構

android{
    // 其餘參數
	
    flavorDimensions('abi', 'version')

    // 建立產品風味
    productFlavors {
        v1 {
            // 關聯緯度
            dimension 'version'
        }

        v2 {
            dimension 'version'
        }

        v3 {
            dimension 'version'
        }

        x86 {
            dimension 'abi'
        }

        armV7 {
            dimension 'abi'
        }
    }
}
複製代碼

經過上面這段代碼,會造成下面這張圖。在 abi 維度上關聯了兩個產品,即 「armV7」 和 「x86」,在 version 的維度上關聯了三個產品,即 「v1」、「v2」 和 「v3」。

而這些維度的交織就會造成最終的風味,即咱們上面所標出來的 「armV7V1」、「armV7V2」、「armV7V3」、「x86V1」、「x86V2」、「x86V3」。

咱們能夠根據不一樣的風味,打出不一樣的apk包,即可以實現一套核心代碼打出多個有些差別的包。

更多的使用咱們在下篇博客講解,咱們先了解下他可配置的參數。

4、productFlavor

productFlavors 下的每一個項最終形式是 productFlavor,即咱們上面說所的 「v1」,「v2」.....

一、productFlavor 存在形式

咱們知道,每一個配置最終會被映射爲一個類,或是一個屬性、或一個方法。productFlavor 也不例外,他會被映射爲 com.android.build.gradle.internal.dsl.ProductFlavor,繼承結構以下

二、productFlavor 的屬性意義

咱們先來一個約定,避免使用的代碼過於冗長。

android {
    productFlavors{
   		
        zincPower{
		// 咱們下面的 「使用方法」 代碼都是基於這一塊,除非特殊說明。
     	}
     	
    }
}
複製代碼

2.1 applicationId

  • 類型:String
  • 描述:應用的id,這裏會覆蓋掉 defaultConfig 中配置的 applicationId。從而可讓咱們打出不一樣的apk包。

defaultConfig 的具體配置能夠看小盆友的另外一篇博文,傳送門

  • 使用方法:
zincPower {
    // applicationId 應用的包名,會覆蓋 defaultConfig 中的 applicationId
    // applicationId 會替換 AndroidManifest.xml 中的 manifest 標籤下 package 的 value
    applicationId "com.zinc.power"
	......省略其餘配置
}
複製代碼

2.2 applicationIdSuffix

  • 類型:String
  • 描述:會追加在 applicationId 字符串的後面,造成最終的包名。這樣也能夠達到一套代碼多個包名的效果。
  • 使用方法:
zincPower {
	applicationIdSuffix '.debug'
}
複製代碼

2.3 consumerProguardFiles

  • 類型:List< File >
  • 描述:這個屬性只做用於咱們建立的 library 中,包括咱們以aar形式導入的 library ,或是直接建立的 library。它的做用是,負責該 library 被進行編譯時的混淆規則,咱們在 主App 的模塊下則能夠不用再管理各個 library 的混淆規則,會直接使用各個 library 的混淆規則文件。
  • 使用方法:
zincPower {
	consumerProguardFiles 'consumer-rules.pro'
	......省略其餘配置
}

// 由於該屬性是一個 List<File> 類型,若是須要多個文件配置,則以下所示
zincPower {
	consumerProguardFiles 'consumer-rules.pro','zincPower-rules.pro'
	......省略其餘配置
}
複製代碼

2.4 dimension

  • 類型:String
  • 描述:風味的維度,指定咱們當前風味所所屬的維度。一個風味必需要有一個維度,並且也只能關聯一個維度。 不然會報如下錯誤
ERROR: Flavor 'v1' has no flavor dimension.
複製代碼
  • 使用方法:
zincPower {
    // 關聯緯度
    dimension 'version'
    
	......省略其餘配置
}
複製代碼

2.5 externalNativeBuild

  • 類型:ExternalNativeBuildOptions
  • 描述:這裏咱們設置 ndk 編譯過程的一些參數。分爲 cmake 和 ndkBuild 兩個參數。
  • 使用方法:
zincPower {
    externalNativeBuild {
        ndkBuild {
            // Passes an optional argument to ndk-build.
            arguments "NDK_MODULE_PATH+=../../third_party/modules"
        }
        // For ndk-build, instead use the ndkBuild block.
        cmake {
             // Passes optional arguments to CMake.
             arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

             // Sets a flag to enable format macro constants for the C compiler.
             cFlags "-D__STDC_FORMAT_MACROS"

             // Sets optional flags for the C++ compiler.
             cppFlags "-fexceptions", "-frtti"

             // Specifies the library and executable targets from your CMake project
             // that Gradle should build.
             targets "libexample-one", "my-executible-demo"
         }
   }
}
複製代碼

cmake 具體參數 傳送門 ndkBuild 具體參數 傳送門

2.6 javaCompileOptions

  • 類型:JavaCompileOptions
  • 描述:配置編譯時 java 的一些參數,例如咱們使用 annotationProcessor 時所須要的參數。
  • 使用方法:
zincPower {
    javaCompileOptions {
        annotationProcessorOptions{
    		arguments = []
    		classNames ''
    		....
    	}
    }
    ......省略其餘配置
}
複製代碼

JavaCompileOptions 能夠配置的具體參數,請進傳送門

2.7 manifestPlaceholders

  • 類型:Map<String, Object>
  • 描述:配置能夠在 AndroidManifest.xml 中替換的參數,咱們可使用這個參數配置不一樣風味的 logo 和 app名字,以及友盟的參數,達到不一樣風味的差別化配置
  • 使用方法:

咱們配置差別化的 logo 和 app名字,則能夠在 gradle 中使用下面這段

android {
    flavorDimensions('abi', 'version')
    productFlavors {
    	// 省略其餘的風味配置 
    	
        x86 {
            dimension 'abi'
    		
    		// 配置不一樣的包名,達到能兩個風味能共存
            applicationId 'com.zinc.bear'
    
            manifestPlaceholders = [
                    logo    : "@drawable/logo_bear",
                    appName : "bear",
            ]
    
    		// 配置簽名
            signingConfig signingConfigs.jiangpengyong
        }
    
        armV7 {
            dimension 'abi'
    
    		// 配置不一樣的包名,達到能兩個風味能共存
            applicationId 'com.zinc.shark'
    
            manifestPlaceholders = [
                    logo    : "@drawable/logo_shark",
                    appName : "shark",
            ]
    
    		// 配置簽名
            signingConfig signingConfigs.xiaopenyou
        }
    }
}
複製代碼

logo的資源圖

而後在 AndroidManifest.xml 中使用,使用 ${你配置的變量名}

<application android:allowBackup="true" android:icon="${logo}" android:label="${appName}" android:roundIcon="${logo}" android:supportsRtl="true" android:theme="@style/AppTheme">
......
複製代碼

最終分別運行後,咱們能夠看到以下效果

2.8 matchingFallbacks

  • 類型:List< String >
  • 描述:用於處理引入的 library 中存在不匹配的風味狀況。
  • 使用方法:

舉個例子: 咱們有一個 x86 的風味 在引入一個 library,而 library 中存在一樣的風味維度,可是沒有相同產品風味,這樣會致使無法匹配,此時,就須要用這個參數。代碼以下:

app 下的 build.gradle

android {
    // 其餘配置
	
    flavorDimensions('abi')
    // 建立產品風味
    productFlavors {
        x86 {
            dimension 'abi'
            matchingFallbacks = ['pro']
        }
}

dependencies {
	// 引入 flavor_x86 library
    x86Implementation project(':flavor_x86')
}
複製代碼

flavor_x86 下的 build.gradle

android {
    // 存在相同的風味維度
    flavorDimensions('abi')
    // 沒有相同的產品風味,須要使用 matchingFallbacks 選擇須要的產品風味
    productFlavors {
        pro {
            dimension 'abi'
        }

        free{
            dimension 'abi'
        }
    }

}
複製代碼

小盆友在github上有個demo,有所幫助就給star吧。

2.9 multiDexEnabled

64K 引用限制問題官方文檔 傳送門

  • 類型:Boolean
  • 描述:是否開啓分包。由於安卓中方法索引值爲兩個字節,四位十六進制的一個數值,即[0, 0xffff],因此最大方法數爲65536個。一旦超出了,就須要進行分包,因此咱們就須要開啓這個參數。
  • 值得一提:咱們能夠在 defaultConfig 中開啓便可,就不須要每一個風味都寫一遍,減小冗餘。

爲了不篇幅過長,使用方法請看小盆友的另外一片博文:defaultConfig——安卓gradle 的 3.8小節

2.10 multiDexKeepFile

  • 類型:File
  • 描述:將咱們須要的類打包進主包,即 classs.dex。咱們在第 2.9 小點,分享到使用了多 dex包處理,有時咱們須要將一些主要的類打包進主包,則可使用該屬性。
  • 使用方法:
zincPower {
    multiDexKeepFile file('multidex-config.txt')
    ...
}
複製代碼

multidex-config.txt 中的書寫則以下,每個文件則爲一行

com/example/MyClass.class
com/example/TestClass.class
複製代碼

2.11 multiDexKeepProguard

  • 類型:File
  • 描述:將咱們須要的類打包進主包,和第 2.10 點的功能相同,區別在於寫法。
  • 使用方法:
zincPower  {
    multiDexKeepFile file('multidex-config.pro')
    ...
}
複製代碼

multidex-config.pro 中的寫法以下

// 將會保留全部的在com.example package的類
-keep class com.example.** { *; }
複製代碼

2.12 ndk

  • 類型:NdkOptions
  • 描述:用於abi過濾
  • 使用方法: 進行以下配置,編譯出來的 Apk包只包含armeabi-v7a,不會包含其餘的架構,例如 "X86"。
zincPower {
    // ndk中,目前只有 abiFilter 一個屬性,因此 ndk 目前來講只用於 abi 的過濾
    ndk {
        abiFilter 'armeabi-v7a'
    }
	...
}
複製代碼

NdkOptions的具體可配參數見官方文檔 傳送門

2.13 proguardFiles

  • 類型:List< File >
  • 描述:配置混淆規則文件,只有 minifyEnabled 設置爲 true 的時候會使用這個參數,文件中須要申明哪些文件不被優化和混淆。
  • 值得一提:由於被混淆後端代碼,類名和方法名都會有所變化,因此進行反射會失敗,這是咱們就須要進行申明他們不被混淆。(這裏只是舉了使用這個參數的一個場景,若是應用原本是正常的,開了混淆後,出現了莫名奇妙的bug,那就思考下是否由於混淆致使了這一bug
  • 使用方法:
zincPower {
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
複製代碼

2.14 signingConfig

  • 類型:SigningConfig

SigningConfig 的可配置參數 傳送門

  • 描述:配置簽名配置。apk包能被安裝是須要被簽名的,咱們直接運行的時候,是使用了系統默認的簽名證書,當咱們要發佈release包時,則須要使用屬於我的或企業的簽名。
  • 使用方法:

(1)咱們須要先在項目根目錄下建立一個 keystore.properties 文件,在文件中寫入對應的配置,如圖所示

(2)在應用級的 build.gradle 中使用以下代碼

// 引入咱們在(1)中建立的配置
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

android {
    compileSdkVersion 28
    buildToolsVersion "29.0.1"
    defaultConfig {
       	// 省略一些配置...
    }

    signingConfigs {
        xiaopenyou {
        	// 使用 keystoreProperties 獲取對應的參數
            keyAlias keystoreProperties['keyAlias2']
            keyPassword keystoreProperties['keyPassword2']
            storeFile file(keystoreProperties['storeFile2'])
            storePassword keystoreProperties['storePassword2']
        }
        // ...其餘簽名配置
    }

    buildTypes {
        // 省略一些配置...
    }

    flavorDimensions('abi', 'version')
    // 建立產品風味
    productFlavors {
		// 省略一些配置...
        armV7 {
            // 省略一些配置...
            signingConfig signingConfigs.xiaopenyou
        }
    }
}
複製代碼

2.15 vectorDrawables

  • 類型:VectorDrawablesOptions
  • 描述:配置矢量圖的參數
  • 使用方法: VectorDrawablesOptions 中只有兩個參數,爲 generatedDensitiesuseSupportLibrary。分別的用處以下
zincPower {
    vectorDrawables {
        // 若是 minSdkVersion 小於 21,只生成mdpi的png
        generatedDensities 'mdpi'

        // 設置爲 true,會忽略 generatedDensities ,會加入svg兼容包,不會再產生png
        useSupportLibrary true
    }
}
複製代碼

矢量圖的用法,能夠看小盆友的另外一片文章

2.16 versionCode

  • 類型:Integer
  • 描述:應用當前的版本值。和 versionName 的區別在小盆友看來,versionCode 是給程序員看的,versionName 是給產品經理和用戶看的。
  • 使用方法:
zincPower {
    versionCode 1000
    ......
}
複製代碼

2.17 versionName

  • 類型:String
  • 描述:應用版本。咱們一般所說的該應用的版本是「1.2.0」,則是由這個值配置的。
  • 使用方法:
zincPower {
    versionName "1.0.0"
    .....
}
複製代碼

2.18 versionNameSuffix

  • 類型:String
  • 描述:追加在第 2.17 小點「版本」的後綴
  • 使用方法:
zincPower {
    // 若是 versionName "1.0.0" ,則最終的版本名爲 1.0.0.test
    versionNameSuffix ".test"
    .....
}
複製代碼

三、productFlavor 的方法意義

3.1 buildConfigField(type, name, value)

  • 描述:咱們能夠在 BuildConfig 類中添加值,最終會在 BuildConfig 中添加以下一行代碼。
// 值的注意的是 value 的值是原樣放置,咱們經過使用方法一節來了解
<type> <name> = <value>
複製代碼
  • 使用方法:
productFlavors {
    x86 {
        // 能夠經過 BuildConfig 進行獲取
        buildConfigField('String', 'name', '"XiaoPenYou"')
        buildConfigField('int', 'age', '26')
    	.....
    }
}
複製代碼

最終會生成以下圖的配置,咱們能夠經過下面代碼進行獲取

String name = BuildConfig.name;
int age = BuildConfig.age;
複製代碼

值的一提的是,咱們設置 String 類型的參數時,須要加上 "" 雙引號(如例子中的name屬性)。切記!

3.2 consumerProguardFile(proguardFile)

  • 描述:和上面分享的 2.3 小點的屬性 consumerProguardFiles 是同樣的做用。只是這裏只能設置一個 混淆文件。
  • 使用方法:
zincPower {
    consumerProguardFile('consumer-rules.pro')
}
複製代碼

3.3 consumerProguardFiles(proguardFiles)

  • 描述:和上面分享的 2.3 小點的屬性 consumerProguardFiles 是同樣的做用,並且也是多個混淆文件。
  • 使用方法:
zincPower {
    consumerProguardFile('consumer-rules.pro', 'zincPower-rules.pro',.....)
}
複製代碼

3.4 maxSdkVersion(maxSdkVersion)

  • 描述:設置應用的最高支持版本,通常咱們不會進行設置
  • 使用方法:
zincPower {
    // 最高支持28版本
    minSdkVersion 28
}
複製代碼

3.5 minSdkVersion(minSdkVersion)

  • 描述:設置應用的最低支持版本
  • 使用方法:
zincPower {
    // 最低支持19版本
    minSdkVersion 19
}
複製代碼

3.6 missingDimensionStrategy(dimension, requestedValue)

  • 類似方法:missingDimensionStrategy(dimension, requestedValues) 區別在於第二個參數能夠設置多個風味。
  • 參數說明: (1)dimension:維度 (2)requestedValue:風味(若是爲 requestedValues 則是風味列表)
  • 描述:忽略在 Library 中的渠道設置,即維度(dimension)和風味(flavor),若是不進行忽略,在進行引入的時候會沒法進行。
  • 使用方法:

咱們的項目結構以下

zinclibrarybuild.gradle 中編寫了以下渠道配置

// 建立 風味維度
flavorDimensions('zinc', 'handsome')
// 建立產品風味
productFlavors {
    minApi13{
        dimension 'zinc'
    }
    minApi23{
        dimension 'zinc'
    }
    x86{
        dimension 'handsome'
    }
    arm64{
        dimension 'handsome'
    }
}
複製代碼

此時若是直接在 appbuild.gradle 中添加依賴,同步時便會出錯

dependencies {
    ...忽略其餘依賴
    implementation project(":zinclibrary")
}
複製代碼

因此咱們須要在 appbuild.gradle 中使用這個參數進行忽略 library 中帶來的維度和風味,即便用以下代碼

zincPower {
    missingDimensionStrategy 'zinc', 'minApi13', 'minApi23'
    missingDimensionStrategy 'handsome', 'x86', 'arm64'
}
複製代碼

3.7 proguardFile(proguardFile)

  • 描述:添加混淆文件,和 2.13小點 的功能一致,只是傳入的是一個文件,這裏就再也不贅述
  • 使用方法:
zincPower {
    proguardFile 'proguard-rules.pro'
}
複製代碼

3.10 proguardFiles(files)

  • 描述:添加混淆文件,和 2.13小點 的功能一致,這裏就再也不贅述
  • 使用方法:
debug {
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
複製代碼

3.11 resConfig(config)

  • 描述:保留的資源配置。
  • 使用用法:
zincPower {
    // 這樣咱們編譯出的apk中,只有 「默認」 和 「中文zh」 兩種資源
    resConfig "zh"
}
複製代碼

3.12 resConfigs(config)

  • 描述:保留的資源配置,和 resConfig 的區別在於,resConfigs 保留多個資源。
  • 使用用法:
zincPower {
    // 這樣咱們編譯出的apk中,只有 「默認」 、 「中文zh」 和 「英文en」 兩種資源
    resConfigs "zh","en"
}
複製代碼

3.13 resValue(type, name, value)

  • 描述:添加 value 資源
  • 使用用法:
zincPower {
    // 添加至 res/value,經過 R.string.age 獲取
    resValue('string', 'age', '12year')
}
複製代碼

3.14 setConsumerProguardFiles(proguardFileIterable)

  • 描述:和 2.3小點 的功能一致,只是寫法不一樣,這裏就再也不贅述
  • 使用方法:
zincPower {
    consumerProguardFiles = [ 'consumer-rules.pro','zincPower-rules.pro' ]
}
複製代碼

3.15 setProguardFiles(proguardFileIterable)

  • 描述:添加混淆文件,和 2.13小點 的功能一致,只是寫法稍微不一樣,這裏就再也不贅述
  • 使用方法:
zincPower {
    proguardFiles = [getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro']
}
複製代碼

3.16 targetSdkVersion(targetSdkVersion)

  • 描述:應用的目標版本。說明咱們已經對指定的版本進行了測試,在開發過程當中可使用至該版本的API,不然會被提示沒法使用。若是不設置,則和 minSdkVersion 的值保持一致。
  • 使用用法:
zincPower {
    targetSdkVersion 28
}
複製代碼

5、寫在最後

Gradle 的配置文件看起來好像挺亂,實際上是由於咱們沒有進行總體的梳理,所謂 「無知最可怕」

若是喜歡的話請給我一個贊,並關注我吧。文章中若有寫的不妥的地方,請評論區或加我微信與我討論吧,共同進步。

歡迎加我微信,進行更多的交流

若是以爲文章有很大的幫助,快來讚揚一次吧😄

相關文章
相關標籤/搜索