之前在瀏覽掘金的時候,看到有大佬寫過一篇文章關於Android ProductFlavor的文章,原文鏈接:
https://juejin.cn/post/6973570453629567012
但是由於之前在公司項目也用過ProductFlavor,發現和大佬用的有些區別,自己就硬着頭皮去看完了官網的文檔(英文不好的痛),原文地址
然後覺得應該記錄下自己的學習歷程
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
下就有如下幾個編譯條件(這裏假設buildType
只有debug
和release
)
1.2 dimension組合配置
當一個module
中定義了不同的dimension
,並且在不同的Flavor
下使用,那麼會組合使用,也就是總共會有 dimension【0】...dimension【n-1】(每個代表dimension
使用Flavor
個數,如果沒有使用,就不需要計入)buldType的個數;其中配置會相互交叉
新建一個module
,其中ProductFlavor
的配置如下
flavorDimensions 'api', 'version'
productFlavors {
demo {
dimension 'version'
}
full {
dimension 'version'
}
minApi24 {
dimension 'api'
}
minApi21 {
dimension "api"
}
}
那麼build variant
的環境會有:
配置個數= api的flavor個數(2)* version的flavor個數*buildType個數(2) = 8個
2.提升使用
前面已經講清楚如何使用dimension
配置,那麼如何實現多渠道里面的不同配置,如app
名,applicationId
,icon
圖標,甚至mainifest
下的配置參數呢。
2.1 defaultConfig配置修改
這就是ProductFlavor
下的第一個特點了,就是可以動態修改module
中defaultConfig
參數,包括:
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)
首先默認的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()]
}
}
}
這個配置應用的運行結果如下
接下來,就是使用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
環境下的包配置如下
再看看,product
環境下的包配置如下
完全生效的。
2.2 使用不同res/java目錄替換配置
可以在app目錄下根據不同的product,使用不同的java/res資源;然後根據不同的flavor,使用不同的配置
這裏,更改兩個參數,string
裏面的app_name
這裏舉例更改:
原main環境下
dev
環境下
product
環境下
運行結果:
2.3 manifestPlaceholders 向mainifest注入資源
在某些情況下,會需要根據不同的配置,更改mainifest下的部分參數配置,比如app的名字或者icon,這裏就需要使用manifestPlaceholders,如果想看官網原文,連接如下,https://developer.android.google.cn/studio/build/manifest-build-variables.html?hl=en
這裏建議 和2.2使用不同res/java目錄替換配置二選一,只使用其中一種
同樣的,可以使用manifestPlaceholders實現上面一樣的效果;
這裏需要注意,flavor
中使用mainifestPlaceholders
一定要指定ENVIRONMENT
,默認環境爲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"
}
}
運行結果如下
2.4 buildConfigField 配置資源
在某些情況下,我們會需要根據不同的環境,加入以下不同的配置,這個也可以使用ProductFlavor中buildConfigField在編譯時,動態配置。
buildConfigField具備三個參數 type(類型,這裏可用基本類型),name(這個在BuildConfig中的名稱),value(這個參數在BuildConfig中的值);具體參數解析如下
如下的配置參數
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
//buildConfigField
buildConfigField "String", "TAG", '"apple"'
buildConfigField "int", "BASE_PORY", '12'
buildConfigField "Boolean", "IS_OK", 'true"
}
}
編譯後 對應module的BuildConfig爲
然後可以在代碼中使用這些資源
2.5 matchingFallbacks和missingDimensionStrategy
這兩個特性當時剛看的時候,看的頭大,而且官網資料寫的很少,最終在stackoverflow看到有人推薦的一篇博文,然後自己試着寫了一些測試代碼,終於是搞定了。文章地址https://kiranrao.in/blog/2020/03/31/gradle-missing-flavors/
2.5.1 matchingFallbacks
首先說matchingFallbacks
的設計背景:在多module
依賴的模式下,如module A
依賴 module B
;如果A
的ProductFlavor
下有 dev
和product
的flavor
,而B中只有dev
;那麼當mudule A
編譯devXXX
的情況下,會正常通過編譯;而編譯product
的情況下,會異常;理由就是B中找不到對應的product
條件的flavor
;而matchingFallbacks
就是用來解決這個問題的
上面說這麼多,不如直接代碼來演示
新建一個module
名字叫flavor1
,它build.gradle
內容如下:
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
}
然後app module
依賴flavor1
,它build.gradle 內容如下:
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
product{
dimension "nation"
}
}
這裏 主module有 dev,product兩個flavor;子module只有一個dev 的flavor
dev
條件下是正常的
然而運行
product
就無法通過了
以上錯誤信息就是背景描述的情況;
其中
matchingFallbacks
格式如下
matchingFallbacks["子module使用flavor1","子module 的使用flavor2",...]
對應主module
下的flavor
在子module
會按照這個配置順序去適配子module
的flavor
所以修改主module
配置(matchingFallbacks
)
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
}
product{
dimension "nation"
//matchingFallbacks 多module匹配條件
matchingFallbacks = ['dev']
}
}
然後再次編譯安裝,ok了;總結一下,這裏當子module
有的flavor
,而主module
存在的flavor
,(dimension
需要一樣)就需要配置matchingFallbacks
使用子mudule
中的flavor
順序。
2.5.2 missingDimensionStrategy
使用條件:當主module中不存在,而子module中存在的dimension,就需要在主module中定義使用哪個dimension下的哪一個flavor;其結構如下:
missingDimensionStrategy["dimension","子module dimension 下的使用flavor"]
首先,創建子module flavor2
,其build.gradle
下,主module
依賴它
flavorDimensions "nations"
productFlavors{
dev{
dimension "nations"
}
product{
dimension "nations"
}
user{
dimension "nations"
}
}
直接運行,運行告警
所以需要按照之前格式指定對應的dimension
使用子module
中哪一個flavor
。
所以這裏可以在主 module
配置
flavorDimensions "nation"
productFlavors{
dev{
dimension "nation"
missingDimensionStrategy 'nations', 'dev'
}
product{
dimension "nation"
missingDimensionStrategy 'nations', 'product'
}
完成配置運行成功
參考
尾巴大不掉 https://juejin.cn/post/6973570453629567012?utm_source=gold_browser_extension
missingDimensionStrategy https://kiranrao.in/blog/2020/03/31/gradle-missing-flavors/
項目地址: