目录
一、前言
二、flavorDimensions 的意义
三、productFlavors的意义
四、productFlavor
五、写在最后
一、前言
有了前两篇博客的铺垫,我们可以来分享下另外两个参数了 flavorDimensions 和 productFlavors,而这两个参数成对出现,可以做一些差分化定义。
前两篇博客为:
1、defaultConfig——安卓gradle
2、buildTypes——安卓gradle
需要事先说明的是,接下来所说的 “意义” 并非官方文档翻译,而是结合了小盆友自己的理解,会比较口语化。
二、flavorDimensions 的意义
flavorDimensions 从单词字面理解知道是 “风味维度”,是需要结合 “产品风味(即productFlavors)” 来一起使用的。
flavorDimensions 的使用会定义出维度,供接下来的 productFlavors 使用。我们举个例子
android {
// 省略其他参数
flavorDimensions('abi', 'version')
}
1
2
3
4
5
使用上面代码,则会定义出两个维度:version 和 abi。一个参数一个维度,我们把它形象化,就可以看成下面这样一张图。而他有什么作用,我们看下一小节。
如果三个参数就可以看成一个三维的空间坐标系,这里的坐标系只是一个形象化的体现。
三、productFlavors的意义
productFlavors 从字面了解是“产品风味”。他需要和一个风味维度对接,否则会报错。
接着我们上面的例子,使用 productFlavors 定义维度上的风味,使用 dimension 关联。
android{
// 其他参数
flavorDimensions('abi', 'version')
// 创建产品风味
productFlavors {
v1 {
// 关联纬度
dimension 'version'
}
v2 {
dimension 'version'
}
v3 {
dimension 'version'
}
x86 {
dimension 'abi'
}
armV7 {
dimension 'abi'
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
通过上面这段代码,会形成下面这张图。在 abi 维度上关联了两个产品,即 “armV7” 和 “x86”,在 version 的维度上关联了三个产品,即 “v1”、“v2” 和 “v3”。
而这些维度的交织就会形成最终的风味,即我们上面所标出来的 “armV7V1”、“armV7V2”、“armV7V3”、“x86V1”、“x86V2”、“x86V3”。
我们可以根据不同的风味,打出不同的apk包,便可以实现一套核心代码打出多个有些差异的包。
更多的使用我们在下篇博客讲解,我们先了解下他可配置的参数。
四、productFlavor
productFlavors 下的每个项最终形式是 productFlavor,即我们上面说所的 “v1”,“v2”…
1、productFlavor 存在形式
我们知道,每个配置最终会被映射为一个类,或是一个属性、或一个方法。productFlavor 也不例外,他会被映射为 com.android.build.gradle.internal.dsl.ProductFlavor,继承结构如下
dsl/ProductFlavor
BaseFlavor
DefaultProductFlavor
BaseConfigImpl
ProductFlavor
BaseConfig
DimensionAware
CoreProductFlavor
Named
2、productFlavor 的属性意义
我们先来一个约定,避免使用的代码过于冗长。
android {
productFlavors{
zincPower{
// 我们下面的 “使用方法” 代码都是基于这一块,除非特殊说明。
}
}
}
1
2
3
4
5
6
7
8
9
2.1 applicationId
类型:String
描述:应用的id,这里会覆盖掉 defaultConfig 中配置的 applicationId。从而可以让我们打出不同的apk包。
defaultConfig 的具体配置可以看小盆友的另一篇博文,传送门。
使用方法:
zincPower {
// applicationId 应用的包名,会覆盖 defaultConfig 中的 applicationId
// applicationId 会替换 AndroidManifest.xml 中的 manifest 标签下 package 的 value
applicationId "com.zinc.power"
......省略其他配置
}
1
2
3
4
5
6
2.2 applicationIdSuffix
类型:String
描述:会追加在 applicationId 字符串的后面,形成最终的包名。这样也可以达到一套代码多个包名的效果。
使用方法:
zincPower {
applicationIdSuffix '.debug'
}
1
2
3
2.3 consumerProguardFiles
类型:List< File >
描述:这个属性只作用于我们创建的 library 中,包括我们以aar形式导入的 library ,或是直接创建的 library。它的作用是,负责该 library 被进行编译时的混淆规则,我们在 主App 的模块下则可以不用再管理各个 library 的混淆规则,会直接使用各个 library 的混淆规则文件。
使用方法:
zincPower {
consumerProguardFiles 'consumer-rules.pro'
......省略其他配置
}
// 因为该属性是一个 List
zincPower {
consumerProguardFiles 'consumer-rules.pro','zincPower-rules.pro'
......省略其他配置
}
1
2
3
4
5
6
7
8
9
10
2.4 dimension
类型:String
描述:风味的维度,指定我们当前风味所所属的维度。一个风味必须要有一个维度,而且也只能关联一个维度。 否则会报以下错误
ERROR: Flavor 'v1' has no flavor dimension.
1
使用方法:
zincPower {
// 关联纬度
dimension 'version'
......省略其他配置
}
1
2
3
4
5
6
2.5 externalNativeBuild
类型:ExternalNativeBuildOptions
描述:这里我们设置 ndk 编译过程的一些参数。分为 cmake 和 ndkBuild 两个参数。
使用方法:
zincPower {
externalNativeBuild {
ndkBuild {
// Passes an optional argument to ndk-build.
arguments "NDK_MODULE_PATH+=../../third_party/modules"
}
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
// Sets a flag to enable format macro constants for the C compiler.
cFlags "-D__STDC_FORMAT_MACROS"
// Sets optional flags for the C++ compiler.
cppFlags "-fexceptions", "-frtti"
// Specifies the library and executable targets from your CMake project
// that Gradle should build.
targets "libexample-one", "my-executible-demo"
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cmake 具体参数 传送门
ndkBuild 具体参数 传送门
2.6 javaCompileOptions
类型:JavaCompileOptions
描述:配置编译时 java 的一些参数,例如我们使用 annotationProcessor 时所需要的参数。
使用方法:
zincPower {
javaCompileOptions {
annotationProcessorOptions{
arguments = []
classNames ''
....
}
}
......省略其他配置
}
1
2
3
4
5
6
7
8
9
10
JavaCompileOptions 可以配置的具体参数,请进传送门
2.7 manifestPlaceholders
类型:Map
描述:配置可以在 AndroidManifest.xml 中替换的参数,我们可以使用这个参数配置不同风味的 logo 和 app名字,以及友盟的参数,达到不同风味的差异化配置。
使用方法:
我们配置差异化的 logo 和 app名字,则可以在 gradle 中使用下面这段
android {
flavorDimensions('abi', 'version')
productFlavors {
// 省略其他的风味配置
x86 {
dimension 'abi'
// 配置不同的包名,达到能两个风味能共存
applicationId 'com.zinc.bear'
manifestPlaceholders = [
logo : "@drawable/logo_bear",
appName : "bear",
]
// 配置签名
signingConfig signingConfigs.jiangpengyong
}
armV7 {
dimension 'abi'
// 配置不同的包名,达到能两个风味能共存
applicationId 'com.zinc.shark'
manifestPlaceholders = [
logo : "@drawable/logo_shark",
appName : "shark",
]
// 配置签名
signingConfig signingConfigs.xiaopenyou
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
logo的资源图
然后在 AndroidManifest.xml 中使用,使用 ${你配置的变量名}
android:icon="${logo}"
android:label="${appName}"
android:roundIcon="${logo}"
android:supportsRtl="true"
android:theme="@style/AppTheme">
......
1
2
3
4
5
6
7
8
最终分别运行后,我们可以看到如下效果
2.8 matchingFallbacks
类型:List< String >
描述:用于处理引入的 library 中存在不匹配的风味情况。
使用方法:
举个例子:
我们有一个 x86 的风味 在引入一个 library,而 library 中存在同样的风味维度,但是没有相同产品风味,这样会导致没法匹配,此时,就需要用这个参数。代码如下:
app 下的 build.gradle
android {
// 其他配置
flavorDimensions('abi')
// 创建产品风味
productFlavors {
x86 {
dimension 'abi'
matchingFallbacks = ['pro']
}
}
dependencies {
// 引入 flavor_x86 library
x86Implementation project(':flavor_x86')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
flavor_x86 下的 build.gradle
android {
// 存在相同的风味维度
flavorDimensions('abi')
// 没有相同的产品风味,需要使用 matchingFallbacks 选择需要的产品风味
productFlavors {
pro {
dimension 'abi'
}
free{
dimension 'abi'
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
小盆友在github上有个demo,有所帮助就给star吧。
2.9 multiDexEnabled
64K 引用限制问题官方文档 传送门
类型:Boolean
描述:是否开启分包。因为安卓中方法索引值为两个字节,四位十六进制的一个数值,即[0, 0xffff],所以最大方法数为65536个。一旦超出了,就需要进行分包,所以我们就需要开启这个参数。
值得一提:我们可以在 defaultConfig 中开启即可,就不需要每个风味都写一遍,减少冗余。
为了避免篇幅过长,使用方法请看小盆友的另一片博文:defaultConfig——安卓gradle 的 3.8小节
2.10 multiDexKeepFile
类型:File
描述:将我们需要的类打包进主包,即 classs.dex。我们在第 2.9 小点,分享到使用了多 dex包处理,有时我们需要将一些主要的类打包进主包,则可以使用该属性。
使用方法:
zincPower {
multiDexKeepFile file('multidex-config.txt')
...
}
1
2
3
4
multidex-config.txt 中的书写则如下,每一个文件则为一行
com/example/MyClass.class
com/example/TestClass.class
1
2
2.11 multiDexKeepProguard
类型:File
描述:将我们需要的类打包进主包,和第 2.10 点的功能相同,区别在于写法。
使用方法:
zincPower {
multiDexKeepFile file('multidex-config.pro')
...
}
1
2
3
4
multidex-config.pro 中的写法如下
// 将会保留所有的在com.example package的类
-keep class com.example.** { *; }
1
2
2.12 ndk
类型:NdkOptions
描述:用于abi过滤
使用方法:
进行如下配置,编译出来的 Apk包只包含armeabi-v7a,不会包含其他的架构,例如 “X86”。
zincPower {
// ndk中,目前只有 abiFilter 一个属性,所以 ndk 目前来说只用于 abi 的过滤
ndk {
abiFilter 'armeabi-v7a'
}
...
}
1
2
3
4
5
6
7
NdkOptions的具体可配参数见官方文档 传送门
2.13 proguardFiles
类型:List< File >
描述:配置混淆规则文件,只有 minifyEnabled 设置为 true 的时候会使用这个参数,文件中需要申明哪些文件不被优化和混淆。
值得一提:因为被混淆后端代码,类名和方法名都会有所变化,所以进行反射会失败,这是我们就需要进行申明他们不被混淆。(这里只是举了使用这个参数的一个场景,如果应用本来是正常的,开了混淆后,出现了莫名奇妙的bug,那就思考下是否因为混淆导致了这一bug)
使用方法:
zincPower {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
1
2
3
2.14 signingConfig
类型:SigningConfig
SigningConfig 的可配置参数 传送门
描述:配置签名配置。apk包能被安装是需要被签名的,我们直接运行的时候,是使用了系统默认的签名证书,当我们要发布release包时,则需要使用属于个人或企业的签名。
使用方法:
(1)我们需要先在项目根目录下创建一个 keystore.properties 文件,在文件中写入对应的配置,如图所示
(2)在应用级的 build.gradle 中使用如下代码
// 引入我们在(1)中创建的配置
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
compileSdkVersion 28
buildToolsVersion "29.0.1"
defaultConfig {
// 省略一些配置...
}
signingConfigs {
xiaopenyou {
// 使用 keystoreProperties 获取对应的参数
keyAlias keystoreProperties['keyAlias2']
keyPassword keystoreProperties['keyPassword2']
storeFile file(keystoreProperties['storeFile2'])
storePassword keystoreProperties['storePassword2']
}
// ...其他签名配置
}
buildTypes {
// 省略一些配置...
}
flavorDimensions('abi', 'version')
// 创建产品风味
productFlavors {
// 省略一些配置...
armV7 {
// 省略一些配置...
signingConfig signingConfigs.xiaopenyou
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2.15 vectorDrawables
类型:VectorDrawablesOptions
描述:配置矢量图的参数
使用方法:
VectorDrawablesOptions 中只有两个参数,为 generatedDensities 和 useSupportLibrary。分别的用处如下
zincPower {
vectorDrawables {
// 如果 minSdkVersion 小于 21,只生成mdpi的png
generatedDensities 'mdpi'
// 设置为 true,会忽略 generatedDensities ,会加入svg兼容包,不会再产生png
useSupportLibrary true
}
}
1
2
3
4
5
6
7
8
9
矢量图的用法,可以看小盆友的另一片文章
2.16 versionCode
类型:Integer
描述:应用当前的版本值。和 versionName 的区别在小盆友看来,versionCode 是给程序员看的,versionName 是给产品经理和用户看的。
使用方法:
zincPower {
versionCode 1000
......
}
1
2
3
4
2.17 versionName
类型:String
描述:应用版本。我们通常所说的该应用的版本是“1.2.0”,则是由这个值配置的。
使用方法:
zincPower {
versionName "1.0.0"
.....
}
1
2
3
4
2.18 versionNameSuffix
类型:String
描述:追加在第 2.17 小点“版本”的后缀
使用方法:
zincPower {
// 如果 versionName "1.0.0" ,则最终的版本名为 1.0.0.test
versionNameSuffix ".test"
.....
}
1
2
3
4
5
3、productFlavor 的方法意义
3.1 buildConfigField(type, name, value)
描述:我们可以在 BuildConfig 类中添加值,最终会在 BuildConfig 中添加如下一行代码。
// 值的注意的是 value 的值是原样放置,我们通过使用方法一节来了解
1
2
使用方法:
productFlavors {
x86 {
// 可以通过 BuildConfig 进行获取
buildConfigField('String', 'name', '"XiaoPenYou"')
buildConfigField('int', 'age', '26')
.....
}
}
1
2
3
4
5
6
7
8
最终会生成如下图的配置,我们可以通过下面代码进行获取
String name = BuildConfig.name;
int age = BuildConfig.age;
1
2
值的一提的是,我们设置 String 类型的参数时,需要加上 “” 双引号(如例子中的name属性)。切记!
3.2 consumerProguardFile(proguardFile)
描述:和上面分享的 2.3 小点的属性 consumerProguardFiles 是一样的作用。只是这里只能设置一个 混淆文件。
使用方法:
zincPower {
consumerProguardFile('consumer-rules.pro')
}
1
2
3
3.3 consumerProguardFiles(proguardFiles)
描述:和上面分享的 2.3 小点的属性 consumerProguardFiles 是一样的作用,而且也是多个混淆文件。
使用方法:
zincPower {
consumerProguardFile('consumer-rules.pro', 'zincPower-rules.pro',.....)
}
1
2
3
3.4 maxSdkVersion(maxSdkVersion)
描述:设置应用的最高支持版本,一般我们不会进行设置
使用方法:
zincPower {
// 最高支持28版本
minSdkVersion 28
}
1
2
3
4
3.5 minSdkVersion(minSdkVersion)
描述:设置应用的最低支持版本
使用方法:
zincPower {
// 最低支持19版本
minSdkVersion 19
}
1
2
3
4
3.6 missingDimensionStrategy(dimension, requestedValue)
相似方法:missingDimensionStrategy(dimension, requestedValues) 区别在于第二个参数可以设置多个风味。
参数说明:
(1)dimension:维度
(2)requestedValue:风味(如果为 requestedValues 则是风味列表)
描述:忽略在 Library 中的渠道设置,即维度(dimension)和风味(flavor),如果不进行忽略,在进行引入的时候会无法进行。
使用方法:
我们的项目结构如下
在 zinclibrary 的 build.gradle 中编写了如下渠道配置
// 创建 风味维度
flavorDimensions('zinc', 'handsome')
// 创建产品风味
productFlavors {
minApi13{
dimension 'zinc'
}
minApi23{
dimension 'zinc'
}
x86{
dimension 'handsome'
}
arm64{
dimension 'handsome'
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
此时如果直接在 app 的 build.gradle 中添加依赖,同步时便会出错
dependencies {
...忽略其他依赖
implementation project(":zinclibrary")
}
1
2
3
4
所以我们需要在 app 的 build.gradle 中使用这个参数进行忽略 library 中带来的维度和风味,即使用如下代码
zincPower {
missingDimensionStrategy 'zinc', 'minApi13', 'minApi23'
missingDimensionStrategy 'handsome', 'x86', 'arm64'
}
1
2
3
4
3.7 proguardFile(proguardFile)
描述:添加混淆文件,和 2.13小点 的功能一致,只是传入的是一个文件,这里就不再赘述
使用方法:
zincPower {
proguardFile 'proguard-rules.pro'
}
1
2
3
3.10 proguardFiles(files)
描述:添加混淆文件,和 2.13小点 的功能一致,这里就不再赘述
使用方法:
debug {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
1
2
3
3.11 resConfig(config)
描述:保留的资源配置。
使用用法:
zincPower {
// 这样我们编译出的apk中,只有 “默认” 和 “中文zh” 两种资源
resConfig "zh"
}
1
2
3
4
3.12 resConfigs(config)
描述:保留的资源配置,和 resConfig 的区别在于,resConfigs 保留多个资源。
使用用法:
zincPower {
// 这样我们编译出的apk中,只有 “默认” 、 “中文zh” 和 “英文en” 两种资源
resConfigs "zh","en"
}
1
2
3
4
3.13 resValue(type, name, value)
描述:添加 value 资源
使用用法:
zincPower {
// 添加至 res/value,通过 R.string.age 获取
resValue('string', 'age', '12year')
}
1
2
3
4
3.14 setConsumerProguardFiles(proguardFileIterable)
描述:和 2.3小点 的功能一致,只是写法不同,这里就不再赘述
使用方法:
zincPower {
consumerProguardFiles = [ 'consumer-rules.pro','zincPower-rules.pro' ]
}
1
2
3
3.15 setProguardFiles(proguardFileIterable)
描述:添加混淆文件,和 2.13小点 的功能一致,只是写法稍微不同,这里就不再赘述
使用方法:
zincPower {
proguardFiles = [getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro']
}
1
2
3
3.16 targetSdkVersion(targetSdkVersion)
描述:应用的目标版本。说明我们已经对指定的版本进行了测试,在开发过程中可以使用至该版本的API,否则会被提示无法使用。如果不设置,则和 minSdkVersion 的值保持一致。
使用用法:
zincPower {
targetSdkVersion 28
}
1
2
3
五、写在最后
Gradle 的配置文件看起来好像挺乱,其实是因为我们没有进行整体的梳理,所谓 “无知最可怕”。
如果喜欢的话请给我一个赞,并关注我吧。文章中如有写的不妥的地方,请评论区与我讨论吧,共同进步。
————————————————
版权声明:本文为CSDN博主「猛猛的小盆友」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37625173/article/details/100867037