由于业务的需要我们有时会构建多个版本的App,比如免费版和付费版同时还要有用于演示的版本、阉割了部分功能的精简版等等。那么我们怎么做才能在同一个项目中创建不同版本的应用呢。
比如现在有这样一个需求:我们要构建同一个应用的免费版和付费版,并且都需要做渠道统计。
prodectFlavors{}代码块大家应该都不陌生在配置多渠道包中我们就要经常用到。比如这样:
android {
productFlavors {
xiaomi {
}
yingyongbao{
}
wandoujia {
}
baidu {
}
...
}
}
如果我们把Android的gradle插件更新到3.0.0及以上你会发现如果我们单纯的只配置prodectFlavors会报错。
ERROR: All flavors must now belong to a named flavor dimension
要想解决这个问题我们需要添加一个属性 flavorDimensions (3.0.0以下也有这个属性只是没配置的话不会报错)。这个属性可以给我们应用的构建添加多个维度。比如这样:我们便给项目添加了两个维度dimension1和dimension2
flavorDimensions "dimension1","dimension2"
ok,我们回头看下需求,两个版本,个个版本都有多个渠道包。那么就我们需要为项目添加两个维度,一产品版本,二渠道。如下配置:
flavorDimensions "mode","channel"
mode表示我们免费版和付费版的维度,channel表示我们的渠道的维度。接下来我们配置prodectFlavors代码块。如下配置了free和paid版本并且配置了两个渠道。
productFlavors{
//项目的不同版本
free{
dimension "mode"
}
paid{
dimension "mode"
}
//渠道
xiaomi{
dimension "channel"
}
yingyongbao{
dimension 'channel'
}
}
配置好后运行Gradle sync。然后我们看下现在项目有几个构建变体build > Select Build Variant点击下来菜单。可以看到我们拥有了8个变体,对应每个版本的每个渠道。
Gradle 创建的构建变体数量等于每个风味维度中的风味数量与您配置的构建类型数量的乘积。在 Gradle 为每个构建变体或对应 APK 命名时,属于较高优先级风味维度的产品风味首先显示,之后是较低优先级维度的产品风味,再之后是构建类型。以上面的构建配置为例,Gradle 可以使用以下命名方案创建总共 8 个构建变体:
构建变体:[free, paid] [xiaomi, yingyongbao] [Debug, Release]
对应 APK:app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
例如,
构建变体:freeXiaomiDebug
对应 APK:app-free-xiaomi-debug.apk
好了,这样我们便解决了第一个需求。但有个问题,这样每个版本的应用都是同一个applicationId上线的话算是同一个应用。所以我们还要改下gradle,为不同版本添加自己的applicationIdSuffix和versionNameSuffix。
productFlavors{
free{
dimension "mode"
applicationIdSuffix ".free"
versionNameSuffix "-free"
}
paid{
dimension "mode"
applicationIdSuffix ".paid"
versionNameSuffix "-paid"
}
...
}
我们也可以直接使用applicationId,因为 defaultConfig 实际上属于 ProductFlavor 类。这意味这我们可以在productFlavors{}代码块中使用与defaultConfig相同的属性,来更改默认的配置。
productFlavors{
free{
dimension "mode"
applicationId "com.xxx.xxx.free"
}
paid{
dimension "mode"
applicationId "com.xxx.xxx.paid"
}
...
}
如果我们有FileProvider相关的配置,别忘了修改下authorities。gradle会在构建时替换${applicationId}
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepath" />
</provider>
经过这些配置,现在我们的应用可以正常上架了。用户可以从各个渠道下载并安装免费版和付费版。
接下来又有了第二个需求:我们需要在免费版中加入广告。
我们可以为我们不同的构建变体设置自己的资源路径。只有根据变体的名字在src下建立同名的文件夹就可以了。现在我们需要为free版本新建一个资源路径,并且需要在布局中添加广告位并加入一些广告相关的代码文件。
和我们熟悉的项目结构一样,开始码代码吧。gradle在项目构建时会根据我们配置的维度优先级merge相同名称的资源。所以很多东西我们不需要在代码里判断版本去适配,直接修改对应的资源就好了。
下面列出free变体的文件路径,供参考。
Java sources: [app\src\free\java]
Manifest file: app\src\free\AndroidManifest.xml
Android resources: [app\src\free\res]
Assets: [app\src\free\assets]
AIDL sources: [app\src\free\aidl]
RenderScript sources: [app\src\free\rs]
JNI sources: [app\src\free\jni]
JNI libraries: [app\src\free\jniLibs]
Java-style resources: [app\src\free\resources]
如果我们发现这个某个变体的资源文件看起来怪怪的,或者代码多出莫名其妙的飘红。请将Build Variants切换到相应的变体。
比如在免费版中需要用到广告的第三方库而付费版中则不需要。我们就可以进行如下配置。(这个库是瞎编的不要管他)
dependencies {
...
freeImplementation 'com.guanggao.duoduo:advkit:1.1.0'
...
}
如果我们想在代码中判断应用是哪个版本,可以利用BuildConfig类。
在代码中做如下判断:
if(BuildConfig.FLAVOR_mode.equals("free")){
//执行广告相关逻辑
}
好结束了,这样我们就基本能够解决不同版本的所以问题了。
参考文档:productflavorDSL,android gradle配置构建变量