Android Product flavor是根据不同的产品需要来的。例如需要用同一套工程编译不同的客户的apk,不同项目的apk。这样就可以在同一个工程定义不同的产品了。
ProductFlavor有两个概念:1.Dimensions(维度) 2.flavor(风味)
Dimensions:就例如我们划分的产品
flavor:flavor是Dimension里面的细分。例如产品里面根据开发环境不同做区分(dev,stage等)
在Gradle编译的时候如果有相应的flavor,会根据flavor进行组合。 不同Dimensions里面的Flavor进行组合。
例如定义如下:
defaultConfig {
applicationId "com.example.productflavor"
minSdk 23
targetSdk 31
versionCode 1
versionName "1.0"
flavorDimensions "product","platform"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
productFlavors {
dev {
dimension "platform"
}
stage {
dimension "platform"
}
h1{
dimension "product"
}
h2{
dimension "product"
}
}
那么BuildVariant里面的build类型有:
devh1debug
devh1release
devh2debug
devh2release
stageh1debug
stageh1release
stageh2debug
stageh2release
各个flavor可以将有差异的代码放到flavor的文件夹中,文件夹以单个的flavor命名,或者根据buildVariant命名都可以。覆盖的规则就是:
buildtype->buildflavor->main
但是这几个文件夹里面只有存在一份包名相同文件名相同的文件,不让系统会报duplicate错误。
这里需要注意的是对于文件夹即带有flavor又带有buildtype的,它的优先级也属于buildtype级别的,几个flavor组合的还是属于buildflavor级别的。
除了使用合并的方式,还可以根据gradle的SourceSets进行源文件目录设定,这个不仅可以设定源文件,还可以设定资源文件等。
资源文件合并和代码的合并不一样,相同的资源文件采用合并的方式进行,例如在string.xml里面如果都包含相同的string,则根据上面的优先级进行覆盖。如果没有则添加一个。
Manifest文件合并和上面两个还是不一样,这个的合并规则比较多,具体可以参考官方的文档,这里就不赘述了。
Manage manifest files | Android Developers
各个module也可以有自己的flavor,如果app的module和子module的flavor不相同或者数量不一样该如何选择呢?这里使用两个属性解决:
matchingFallbacks
假设有两个module: module1和module2,module1依赖module2。两个module分别定义productFalvor如下:
Module1:
flavorDimensions "platform"
productFlavors{
dev{
dimension "platform"
}
product{
dimension "platform"
}
}
Module2:
flavorDimensions "platform"
productFlavors{
dev{
dimension "platform"
}
}
如果编译dev版本,那么Module1和Module2都会选择dev的flavor,但是如果编译product那么Module2选择哪一个呢?因为Module2中没有product
的flavor,所以这里会出错,因为Module1不知道在编译product的时候Module2该选择哪一个flavor,所以这里就需要使用 matchingFallbacks
:
Module1:
flavorDimensions "platform"
productFlavors{
dev{
dimension "platform"
}
product{
dimension "platform"
matchingFallbacks = ['dev']
}
}
这个的意思是,如果在依赖的模块中缺少相应的flavor那么就依次使用Module中的其他flavor,在我们的例子中的意思就是如果依赖的module中没有product的flavor那么就使用module中的dev
flavor.
注意 大家看到Module1和Module2中使用了相同的flavorDimensions
,经过测试如果不适用相同的flavorDimensions
,那么就算选择dev也会通用出错。
missingDimensionStrategy
上面讲的是主Module多,子Module少的问题,那么如果主Module少,而子Module多了该如何?missingDimensionStrategy
就是用来解决这个问题的。
例如Module1依赖Module2,定义如下:
Module1:
flavorDimensions "platform"
productFlavors{
dev{
dimension "platform"
}
stage{
dimension "platform"
//matchingFallbacks = ['dev']
}
}
Module2:
flavorDimensions "platform"
productFlavors{
dev{
dimension "platform"
}
stage{
dimension "platform"
}
product{
dimension "platform"
}
}
Module2中比Module1多了product
。
可以修改Module1的gradle如下:
flavorDimensions "platform"
productFlavors{
dev{
dimension "platform"
missingDimensionStrategy "platform","dev"
}
stage{
dimension "platform"
missingDimensionStrategy "platform","product","state"
}
}
对child Module的flavor做一个映射。格式如下:
missingDimensionStrategy "dimension","child module flavor"