Android Studio
自从升级到 3.0
之后,gradle
的玩法也随之变得更加丰富起来,今天就来讲讲有关 flavorDimensions
(官网翻译过来是风味维度)的配置。
Android Studio3.0
之前,进行多模块依赖开发的情况下,项目是正常运行的,然而把 studio
升级到 3.0
之后,原本的项目就出现了问题,具体问题如下:
Error:All flavors must now belong to a named flavor dimension.Learn more at
https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
项目是没问题的,那么就应该是配置上出了问题,但这又是什么鬼?
经过了一番的折腾,终于明白了是怎么回事。直译过来的话就是所有的风味现在必须属于一个已命名的风味维度。官网提供的解决方式是:
// Specifies a flavor dimension.
flavorDimensions "color"
productFlavors {
red {
// Assigns this product flavor to the 'color' flavor dimension.
// This step is optional if you are using only one dimension.
dimension "color"
...
}
blue {
dimension "color"
...
}
}
在 defaultConfig
里面加入 flavorDimensions
,定义风味维度(也就是命名风味维度)。
然后在产品风味中指定所属的风味维度。
好了,以上只是针对出现的问题进行解决,接下来就是针对 flavorDimensions
进行一些验证。
多维度理解
其实这涉及到了版本差异化打包的内容,如果说 3.0
以前的版本差异化打包更多的是为了厂商定制的,那么 3.0
以后的版本差异化打包就是在厂商的基础之上加入了机型,渠道等一些参数,变成了多个维度的产品。
也就是说之前的一个产品只有一个参数进行描述的话,现在就可以为其增加多个参数进行配置,比如 A
厂商的 A
渠道的A机型、 A
厂商的 B
渠道的 C
机型等,维度越多,产品的样式越发丰富。
好了,理论说完,接下来就是进行通俗易懂的一些示例了,只有实践才能让自己检验到真理。
新建项目,然后在 app/build.gradle
文件里配置两个风味维度(“company”,“channel”)
,如下:
defaultConfig {
applicationId "com.voctex.flavorsapp"
minSdkVersion 18
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "company","channel"
}
然后进行产品的多维度配置(完整配置在文章下面):
productFlavors{
//随便命名,建议根据该维度的具体信息进行命名
companyA{
dimension "company"
}
companyB{
dimension "company"
}
channelA{
dimension "channel"
}
channelB{
dimension "channel"
}
}
配置完之后进行 gradle
构建,如果用 Terminal
命令直接构建打包的话,用如下命令:
//windows
gradlew :app:assembleRelease
//mac
./gradlew :app:assembleRelease
也可以直接用 studio
进行打包,在最右边有个 Gradle
,里面有很多 task
,直接选择 assembleRelease
,如图:
![](https://img.haomeiwen.com/i2139461/330a32cf904f271e.png)
打包构建之后就会出现多个维度的产品,对应如下,如图:
![](https://img.haomeiwen.com/i2139461/cb07a0c94fa019f1.png)
可以理解为总共有两个维度,公司(company)
和渠道(channel)
,这里公司的维度排前面(排序先后有要求,下面会讲到),所以所有的产品就是,A
公司的 A
渠道产品,A
公司的 B
渠道产品,B
公司的 A
渠道产品,B
公司的 B
渠道产品。
可见,增加维度之后,版本差异化的内容就更为丰富了。
上面说了,维度的定义先后是有要求的,不可随便,下面为了验证这个说法进行了一项测试,我们在 productFlavors
里给每一个特点产品定义一个常量,常量的值就是该特点产品的名字。如下:
productFlavors{
companyA{
dimension "company"
buildConfigField "String","FLAVOR_NAME","\"companyA\""
}
companyB{
dimension "company"
buildConfigField "String","FLAVOR_NAME","\"companyB\""
}
channelA{
dimension "channel"
buildConfigField "String","FLAVOR_NAME","\"channelA\""
}
channelB{
dimension "channel"
buildConfigField "String","FLAVOR_NAME","\"channelB\""
}
}
这里有个要注意的点就是在 BuildConfig
定义 String
的常量时,需要把双引号也加进去。
然后进行跟刚才一样的构建,对比几个风味维度的 BuildConfig
文件里的这个 FLAVOR_NAME
常量,会发现总是显示第一维度 company
的值,而第二维度 channel
的值并不存在,所以当产生多维度的产品时,定义的一些常量总是以第一维度的配置为准。结果如下:
BuildConfig.java
文件生成后会在app/build/generated/source/buildConfig/companyAChannelA/release/com/voctex/flavorsapp/BuildConfig.java
![](https://img.haomeiwen.com/i2139461/b9fbaf78349afc81.png)
-------------------------------------------图片分割线------------------------------------------
![](https://img.haomeiwen.com/i2139461/ccbe5fe04215abfc.png)
-------------------------------------------图片分割线------------------------------------------
![](https://img.haomeiwen.com/i2139461/f02f15693b969a3d.png)
-------------------------------------------图片分割线------------------------------------------
![](https://img.haomeiwen.com/i2139461/ad18537892b2172a.png)
实验证明,当你在各个维度各自定义了同一个常量的值,总是以第一维度的为准,只有第一维度的定义或者说是修改才是有效的。
对了,忘记加上完整的配置信息,重新贴上:
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.voctex.flavorsapp"
minSdkVersion 18
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "company","channel"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors{
companyA{
dimension "company"
buildConfigField "String","FLAVOR_NAME","\"companyA\""
}
companyB{
dimension "company"
buildConfigField "String","FLAVOR_NAME","\"companyB\""
}
channelA{
dimension "channel"
buildConfigField "String","FLAVOR_NAME","\"channelA\""
}
channelB{
dimension "channel"
buildConfigField "String","FLAVOR_NAME","\"channelB\""
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
// testImplementation 'junit:junit:4.12'
// androidTestImplementation 'com.android.support.test:runner:1.0.2'
// androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
因此,在项目中可以通过如下方式分别实现代码逻辑(以下通过FLAVOR变量控制,也可使用或搭配其他变量):
比如本地工具类 Utils.java 中定义了对应的字符串变量,对应 BuildConfig.java中生成的值:
...
public static final String COMPANYA_CHANNELA= "companyAchannelA";
public static final String COMPANYA_CHANNELB= "companyAchannelB";
...
然后其它功能类的代码中就可以通过判断当前的配置变量实现对应型号的逻辑:
...
if (Utils.COMPANYA_CHANNELA.equals(BuildConfig.FLAVOR)) {
//公司 A 产品 A 想实现的代码逻辑
} else if (Utils.COMPANYA_CHANNELB.equals(BuildConfig.FLAVOR)) {
//公司 A 产品 B 想实现的代码逻辑
} else {
//默认配置平台想实现的代码逻辑
}
...
网友评论