ProductFlavor多渠道的神器

之前在浏览掘金的时候,看到有大佬写过一篇文章关于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

然后觉得应该记录下自己的学习历程

image.png

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

image.png

1.2 dimension组合配置

当一个module中定义了不同的dimension,并且在不同的Flavor下使用,那么会组合使用,也就是总共会有 dimension【0】...dimension【n-1】(每个代表dimension使用Flavor个数,如果没有使用,就不需要计入)buldType的个数;其中配置会相互交叉

image.png

新建一个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个

image.png

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

image.png

首先默认的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()]
            }
        }
    }

这个配置应用的运行结果如下

image.png

接下来,就是使用ProductFlavor的情况

image.png
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环境下的包配置如下

image.png

再看看,product环境下的包配置如下

image.png

完全生效的。

2.2 使用不同res/java目录替换配置

可以在app目录下根据不同的product,使用不同的java/res资源;然后根据不同的flavor,使用不同的配置

image.png

这里,更改两个参数,string里面的app_name

这里举例更改:
原main环境下

image.png
image.png

dev环境下

image.png
image.png

product环境下

image.png
image.png

运行结果:

image.png

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

image.png

mainifest文件

image.png

string.xml

image.png

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"
        }
    }

运行结果如下

image.png

2.4 buildConfigField 配置资源

在某些情况下,我们会需要根据不同的环境,加入以下不同的配置,这个也可以使用ProductFlavor中buildConfigField在编译时,动态配置。

buildConfigField具备三个参数 type(类型,这里可用基本类型),name(这个在BuildConfig中的名称),value(这个参数在BuildConfig中的值);具体参数解析如下

image.png

如下的配置参数

 flavorDimensions "nation"
    productFlavors{
        dev{
            dimension "nation"
            //buildConfigField
            buildConfigField "String", "TAG", '"apple"'
            buildConfigField "int", "BASE_PORY", '12'
            buildConfigField "Boolean", "IS_OK", 'true"

        }
      }

编译后 对应module的BuildConfig为

image.png

然后可以在代码中使用这些资源

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

image.png

dev条件下是正常的

image.png

然而运行product就无法通过了

image.png

以上错误信息就是背景描述的情况;
其中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"
        }
    }

直接运行,运行告警


cbae56292f318b7203ee2b052c6a7d8.png

所以需要按照之前格式指定对应的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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容