Android渠道包和马甲包配置
1.背景
2.基本原理
在Android Gradle中,定义了一个叫Build Variant的概念。一个Build Variant = Build Type + Product Flavor 。 也就是构建类型(如比release、debug) + 构建渠道(比如red、blue).它们组合起来就是:redRelease、redDebug、blueRelease、blueDebug。示例如下:
buildTypes配置
android {
...
buildTypes {
debug {
...
}
release {
...
}
}
}
productFlavors配置 官方文档 :build-variants
android {
...
// 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"
...
}
}
}
BuildVariants 预览
3.具体实现
对于build.gradle属性的详细解释可以参考: Android App模块下的的build.gradle配置详解
配置signingConfigs
...
signingConfigs {
release {
def keystoreProperties = new Properties()
rootProject.file("keystore/debugkey.properties").withInputStream {
keystoreProperties.load(it)
}
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = rootProject.file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
}
}
buildTypes {
debug {
...
}
release {
...
signingConfig signingConfigs.release
}
}
我个人倾向于创建一个文件夹单独管理.jks文件,通过读取自己创建的.properties文件来获取定义的属性。上面file(“ keystore/debugkey.properties”).withInputStream{}是一个闭包函数,可以自动关闭流。
配置buildTypes
...
buildTypes {
debug {
applicationIdSuffix ".debug" //applicationId 追加后缀名 .debug
versionNameSuffix ".debug" //versionName 追加后缀名 .debug
}
release {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
customType {
initWith debug //可以完全复制 debug 的所有属性
minifyEnabled true //自定义打开混淆
}
}
在代码中获取:
//获取buildConfigField的值
val API = BuildConfig.DEBUG_API_URL
配置productFlavor
...
flavorDimensions "color"
productFlavors {
red {
dimension "color"
applicationId "com.example.red"
resConfigs 'zh' //或者 resConfigs “hdpi", “xhdpi", “xxhdpi" ,用来配置哪些类型的资源才被打到包中去
//applicationId 应用的包名,会覆盖 defaultConfig 中的 applicationId,同时applicationId 会替换 AndroidManifest.xml 中的 manifest 标签下 package 的 value.
manifestPlaceholders = [ //修改 AndroidManifest.xml 里渠道变量
CHANNEL: "red"
]
//动态修改 常量
// buildConfigField "int", "age", "10" //自定义 int 值
// buildConfigField "Boolean", "openLog", "true" //自定义 boolean 值
// buildConfigField "String", "DEBUG_API_URL", "\"http://www.xxx.com\"" //自定义String 值
//动态在string.xml 添加字段(string.xml中不能有这个字段,会重名),不建议这样添加,因为国际化的时候这里没办法处理
// resValue "string", "app_name", "百度"
// resValue "bool", "auto_updates", 'false'
}
blue {
dimension "color"
applicationId "com.example.blue"
resConfigs 'cn'
manifestPlaceholders = [
CHANNEL: "blue"
]
}
}
//AndroidManifest.mxl 这样就可以通过获取application
...
<application
...>
<!--通过gradle和AndroidManifest的配置就可以在代码里获取application meta-data的值了 -->
<meta-data android:name="CHANNEL" android:value="${CHANNEL}"/>
...
</application>
applicationId是应用程序的唯一标识,用于指写生成的APP的包名,默认情况下是null。若为null,则会在建的时候从AndroidManifest.xml文件中配置的manifest标签的package属性读取,该标识用于上传到应用店区分不同的应用
配置sourceSets
Android 项目中,引入了配置sourceSets来管理目录。代码的摆放位置都是约定好的,但是我们可以使用sourceSets来从新配置路径,举个例子:
...
sourceSets {
//sourceSets 下可以装载多个 sourceSet,我们这里的 main,red和 blue即为 sourceSet
main {
//main 为主干,其他的flavor设置为分支,分支的设置会合并到主干中,例如这里的【red flavor】的配置会合并 main 的配置。
...
}
red {
//sourceSets 可以针对不同的 flavor 进行个性化配置
res.srcDirs = ['src/main/res-red']
java.srcDirs = ['src/red/java']
...
}
blue {
res.srcDirs = ['src/main/res-blue']
zh.java.srcDirs = ['src/blue/java']
...
}
}
//注意 'src/main/res-prod' 和 'src/main/res-uat' 需要自己手动创建;
4.修改应用名称和logo
方式一:在工程目录下创建和flavor名称相同的文件夹 (Google推荐)
在main的同级目录下,有几个渠道就新建几个渠道的文件夹,这种方式在程序编译打包的时候会优先选择flavor目录下的资源,如果main包下存在同名资源则进行替换,否则会和main包的资源进行合并。
方式二:使用manifestPlaceholders
build.gradle脚本配置manifestPlaceholders
...
android {
defaultConfig {
... ...
manifestPlaceholders = [my_app_ame: "demo1", my_app_icon: "@mipmap/logo1"]
}
// 依据debug/release变动的话设置如下
buildTypes {
debug {
manifestPlaceholders = [my_app_ame: "demo1", my_app_icon: "@mipmap/logo1"]
}
}
// 依据flavors变动的话设置如下
flavorDimensions "color"
productFlavors {
red {
...
dimension "color"
manifestPlaceholders = [my_app_ame: "demo1", my_app_icon: "@mipmap/logo1"]
}
blue {
...
dimension "color"
manifestPlaceholders = [my_app_ame: "demo2", my_app_icon: "@mipmap/logo2"]
}
}
}
defaultConfig实际上属于productFlavors,提供所有变体的默认配置。buildType也可视作一个变种维度flavorDimensions, 并且默认有debug和release两个变体,所以其实有些属性是通用的。
对应的AndroidManifest.xml
...
<application
android:icon="${my_app_icon}"
android:label="${my_app_ame}">
···
</application>
5.马甲包有时候需要垃圾代码
参考插件:AndroidJunkCode
6.总结
通过以上配置就可以利用Gradle实现差异化构建,这也是google官方demo中推荐的方式。 对于替换资源的需求其实无论是利用manifestPlaceholders、buildConfigField、sourceSets还是通过创建和flavor名称相同的文件夹都能实现,具体想怎样完全看你自己。
除了使用官方的方式以外还可以利用apktool解包之后对资源进行替换,当然还有一些优秀的三方框架可供选择:walle、packer-ng-plugin 等。
留下评论