之前在瀏覽掘金的時候,看到有大佬寫過一篇文章關(guān)于Android ProductFlavor的文章,原文鏈接:
https://juejin.cn/post/6973570453629567012
但是由于之前在公司項目也用過ProductFlavor,發(fā)現(xiàn)和大佬用的有些區(qū)別,自己就硬著頭皮去看完了官網(wǎng)的文檔(英文不好的痛),原文地址
然后覺得應(yīng)該記錄下自己的學(xué)習(xí)歷程
1.ProductFlavor的簡單使用
1.1 dimension簡單使用
首先,是在module的目錄下(可以是application,library)中build.gradle中,配置信息如下
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
product{
dimension "nation"
}
user{
dimension "nation"
}
}
其中,productFlavors下每個flavor都必須有一個dimension(Android Gradle Plugin 3.0.0以后引入);這樣build variant下就有如下幾個編譯條件(這里假設(shè)buildType只有debug和release)
1.2 dimension組合配置
當(dāng)一個module中定義了不同的dimension,并且在不同的Flavor下使用,那么會組合使用,也就是總共會有 dimension【0】...dimension【n-1】(每個代表dimension使用Flavor個數(shù),如果沒有使用,就不需要計入)buldType的個數(shù);其中配置會相互交叉
新建一個module,其中ProductFlavor的配置如下
flavorDimensions 'api', 'version'
productFlavors {
demo {
dimension 'version'
}
full {
dimension 'version'
}
minApi24 {
dimension 'api'
}
minApi21 {
dimension "api"
}
}
那么build variant的環(huán)境會有:
配置個數(shù)= api的flavor個數(shù)(2)* version的flavor個數(shù)*buildType個數(shù)(2) = 8個
2.提升使用
前面已經(jīng)講清楚如何使用dimension配置,那么如何實現(xiàn)多渠道里面的不同配置,如app名,applicationId,icon圖標(biāo),甚至mainifest下的配置參數(shù)呢。
2.1 defaultConfig配置修改
這就是ProductFlavor下的第一個特點了,就是可以動態(tài)修改module中defaultConfig參數(shù),包括:
applicationId,minSdkVersion,targetSdkVersion,versionCode,versionName,javaCompileOptions等配置
(具體有哪些可以查這個地址https://developer.android.google.cn/reference/tools/gradle-api/7.1/com/android/build/api/dsl/BaseFlavor?hl=en)
首先默認(rèn)的defaultConfig配置
defaultConfig {
applicationId "com.example.myandroidkotlin"
minSdkVersion 18
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
missingDimensionStrategy 'consumer', 'consumed'
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
這個配置應(yīng)用的運(yùn)行結(jié)果如下
接下來,就是使用ProductFlavor的情況
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
//defaultconfig
applicationId "com.example.myandroidkotlin.dev"
minSdkVersion 18
targetSdkVersion 30
versionCode 101
versionName "1.0.1"
}
product{
dimension "nation"
//defaultconfig
applicationId "com.example.myandroidkotlin.product"
minSdkVersion 16
targetSdkVersion 29
versionCode 120
versionName "1.2.0"
}
}
首先,dev環(huán)境下的包配置如下
再看看,product環(huán)境下的包配置如下
完全生效的。
2.2 使用不同res/java目錄替換配置
可以在app目錄下根據(jù)不同的product,使用不同的java/res資源;然后根據(jù)不同的flavor,使用不同的配置
這里,更改兩個參數(shù),string里面的app_name
這里舉例更改:
原main環(huán)境下
dev環(huán)境下
product環(huán)境下
運(yùn)行結(jié)果:
2.3 manifestPlaceholders 向mainifest注入資源
在某些情況下,會需要根據(jù)不同的配置,更改mainifest下的部分參數(shù)配置,比如app的名字或者icon,這里就需要使用manifestPlaceholders,如果想看官網(wǎng)原文,連接如下,https://developer.android.google.cn/studio/build/manifest-build-variables.html?hl=en
這里建議 和2.2使用不同res/java目錄替換配置二選一,只使用其中一種
同樣的,可以使用manifestPlaceholders實現(xiàn)上面一樣的效果;
這里需要注意,flavor中使用mainifestPlaceholders一定要指定ENVIRONMENT,默認(rèn)環(huán)境為main(也就是資源目錄下main文件)
引入新的icon
mainifest文件
string.xml
build.gradle 配置信息
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
manifestPlaceholders=[ENVIRONMENT:"main",
app_icon: "@mipmap/newlogo",
app_name:"@string/app_name_dev"]
}
product{
dimension "nation"
manifestPlaceholders=[ENVIRONMENT:"main",
app_icon: "@mipmap/newlogo",
app_name:"@string/app_name_product"
}
}
運(yùn)行結(jié)果如下
2.4 buildConfigField 配置資源
在某些情況下,我們會需要根據(jù)不同的環(huán)境,加入以下不同的配置,這個也可以使用ProductFlavor中buildConfigField在編譯時,動態(tài)配置。
buildConfigField具備三個參數(shù) type(類型,這里可用基本類型),name(這個在BuildConfig中的名稱),value(這個參數(shù)在BuildConfig中的值);具體參數(shù)解析如下
如下的配置參數(shù)
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
//buildConfigField
buildConfigField "String", "TAG", '"apple"'
buildConfigField "int", "BASE_PORY", '12'
buildConfigField "Boolean", "IS_OK", 'true"
}
}
編譯后 對應(yīng)module的BuildConfig為
然后可以在代碼中使用這些資源
2.5 matchingFallbacks和missingDimensionStrategy
這兩個特性當(dāng)時剛看的時候,看的頭大,而且官網(wǎng)資料寫的很少,最終在stackoverflow看到有人推薦的一篇博文,然后自己試著寫了一些測試代碼,終于是搞定了。文章地址https://kiranrao.in/blog/2020/03/31/gradle-missing-flavors/
2.5.1 matchingFallbacks
首先說matchingFallbacks的設(shè)計背景:在多module依賴的模式下,如module A依賴 module B ;如果A的ProductFlavor下有 dev和product的flavor,而B中只有dev;那么當(dāng)mudule A編譯devXXX的情況下,會正常通過編譯;而編譯product的情況下,會異常;理由就是B中找不到對應(yīng)的product 條件的flavor;而matchingFallbacks就是用來解決這個問題的
上面說這么多,不如直接代碼來演示
新建一個module名字叫flavor1,它build.gradle內(nèi)容如下:
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
}
然后app module依賴flavor1,它build.gradle 內(nèi)容如下:
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
product{
dimension "nation"
}
}
這里 主module有 dev,product兩個flavor;子module只有一個dev 的flavor
dev條件下是正常的
然而運(yùn)行
product就無法通過了
以上錯誤信息就是背景描述的情況;
其中
matchingFallbacks格式如下
matchingFallbacks["子module使用flavor1","子module 的使用flavor2",...]
對應(yīng)主module下的flavor在子module會按照這個配置順序去適配子module的flavor
所以修改主module配置(matchingFallbacks)
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
product{
dimension "nation"
//matchingFallbacks 多module匹配條件
matchingFallbacks = ['dev']
}
}
然后再次編譯安裝,ok了;總結(jié)一下,這里當(dāng)子module有的flavor,而主module存在的flavor,(dimension需要一樣)就需要配置matchingFallbacks使用子mudule中的flavor順序。
2.5.2 missingDimensionStrategy
使用條件:當(dāng)主module中不存在,而子module中存在的dimension,就需要在主module中定義使用哪個dimension下的哪一個flavor;其結(jié)構(gòu)如下:
missingDimensionStrategy["dimension","子module dimension 下的使用flavor"]
首先,創(chuàng)建子module flavor2,其build.gradle下,主module依賴它
flavorDimensions "nations"
productFlavors{
dev{
dimension "nations"
}
product{
dimension "nations"
}
user{
dimension "nations"
}
}
直接運(yùn)行,運(yùn)行告警

所以需要按照之前格式指定對應(yīng)的dimension 使用子module中哪一個flavor。
所以這里可以在主 module配置
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
missingDimensionStrategy 'nations', 'dev'
}
product{
dimension "nation"
missingDimensionStrategy 'nations', 'product'
}
完成配置運(yùn)行成功
參考
尾巴大不掉 https://juejin.cn/post/6973570453629567012?utm_source=gold_browser_extension
google官網(wǎng) https://developer.android.google.cn/reference/tools/gradle-api/7.1/com/android/build/api/dsl/ProductFlavor
missingDimensionStrategy https://kiranrao.in/blog/2020/03/31/gradle-missing-flavors/
項目地址: