ProductFlavor多渠道的神器 1.ProductFlavor的簡單使用 2.提升使用 參考

之前在瀏覽掘金的時候,看到有大佬寫過一篇文章關於Android ProductFlavor的文章,原文鏈接:
https://juejin.cn/post/6973570453629567012

但是由於之前在公司項目也用過ProductFlavor,發現和大佬用的有些區別,自己就硬着頭皮去看完了官網的文檔(英文不好的痛),原文地址

https://developer.android.google.cn/reference/tools/gradle-api/7.1/com/android/build/api/dsl/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只有debugrelease

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名,applicationIdicon圖標,甚至mainifest下的配置參數呢。

2.1 defaultConfig配置修改

這就是ProductFlavor下的第一個特點了,就是可以動態修改moduledefaultConfig參數,包括:
applicationIdminSdkVersiontargetSdkVersionversionCodeversionNamejavaCompileOptions等配置
(具體有哪些可以查這個地址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 ;如果AProductFlavor下有 devproductflavor,而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會按照這個配置順序去適配子moduleflavor

所以修改主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

google官網 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/

項目地址:

https://github.com/jiaoery/MyAndroidKotlin

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章