Android ProductFlavor

相野
2023-12-01

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文件合并

Manifest文件合并和上面两个还是不一样,这个的合并规则比较多,具体可以参考官方的文档,这里就不赘述了。
Manage manifest files | Android Developers

module BuildVariant的选择

各个module也可以有自己的flavor,如果app的module和子module的flavor不相同或者数量不一样该如何选择呢?这里使用两个属性解决:

  1. 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也会通用出错。

  2. 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"
    
 类似资料:

相关阅读

相关文章

相关问答