赞
踩
之前为了在同一台手机能同时安装测试包和生产包,采用配置buildType的方式来实现,相比于flavor,感觉是挺轻量又恰到好处的配置,具体见通过配置applicationId来实现测试包和生产包安装在同一台手机上。最近因为业务需要,需要多个渠道的包了,这就必须要用到flavor这个大杀器了。一路配置下来,感觉还挺顺,下面就具体记录一下。
先说一下需求,增加一个渠道
大概就是这么些东西需要根据渠道来配置的。不过还有一些潜在的东西也需要按渠道来配置,如:
由于我还保留着degbug与release包使用不同的applicationId,实际上两个渠道共4个包都是不同id的,某些参数除了要根据渠道区分还要再根据buildType做相应的配置。
一、先把flavor配置起来,在app的build.gradle文件中的 android
代码块中添加
// 定义flavor的dimension,至少要有一个dimension,名字随便取,这个必须要的,不然会报错
flavorDimensions "version"
// 渠道包定义,默认定义的名称就是渠道名称
productFlavors {
// google渠道
google {
applicationId = "com.my.google"
}
// twitter渠道
twitter {
applicationId = "com.my.twitter"
}
}
这里配置了两个渠道,并指定了它们各自的applicationId,值得注意的是必须要先设置flavorDimensions,值可以随便取。
二、配置签名
//配置签名
signingConfigs {
google {
storeFile file("D:/docs/keyStore/googleKeyStore.jks")
storePassword "111111"
keyAlias "key0"
keyPassword "222222"
}
twitter {
storeFile file("D:/docs/keyStore/twitterKeyStore.jks")
storePassword "333333"
keyAlias "key1"
keyPassword "444444"
}
}
storeFile是KeyStore.jks文件所在的目录,这里配置的所有内容都是创建jks的时候自己填的。
jks的创建
as菜单 Build–>Generate Signed Bundle/APK…->选中APK–>Next–>Create new…
在打开的填写文件路径、密码等内容,一路next就行了
配置好之后,在flavor块中加上对签名的引用,如下
productFlavors {
// google渠道
google {
applicationId = "com.my.google"
signingConfig signingConfigs.google
}
// twitter渠道
twitter {
applicationId = "com.my.twitter"
signingConfig signingConfigs.twitter
}
}
三、 配置只需要区分渠道而不需要区分buildType的参数,如:页面中的图片,接口参数等
这些参数都可以用buildConfigField方法来设置,这个方法将在BuildConfig类中添加一个字段,它接受三个参数,第一个是数据类型,第二个是字段名,第三个是字段值,如:
buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_google"
buildConfigField "String", "LOGIN_TEXT", "请输入google账号"
在java代码中直接用 BuildConfig.LOGIN_ICON
或 BuildConfig.LOGIN_TEXT
来引用对应的图片或文字,非常方便。将这个代码写在flavor块内,如下:
productFlavors { // google渠道 google { applicationId = "com.my.google" signingConfig signingConfigs.google buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_google" buildConfigField "String", "LOGIN_TEXT", "\"请输入google账号\"" } // twitter渠道 twitter { applicationId = "com.my.twitter" signingConfig signingConfigs.twitter buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_twitter" buildConfigField "String", "LOGIN_TEXT", "\"请输入twitter账号\"" } }
四、配置buildType的内容,有部分内容还要区分flavor,如:appName,百度地图key等
buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 配置生产环境url buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\"" // 要区分渠道的内容 if (mFlavor == "google") { // google渠道生产版百度地图key manifestPlaceholders = [baiduMapKey : "11111111111", fileProviderAuthority: "aaaaaaaa", logo : "R.drawable.logo_google_release" ] resValue 'string', 'app_name', "我的应用google版" resValue 'string', 'authority', "aaaaaaaa" } else { // twitter渠道生产版百度地图key manifestPlaceholders = [baiduMapKey : "22222222", fileProviderAuthority: "bbbbbbbbb", logo : "R.drawable.logo_twitter_release", ] resValue 'string', 'app_name', "我的应用twitter版" resValue 'string', 'authority', "bbbbbbbbb" } } debug { // debug包的applicationId在生产包的后面加上后缀".abc" applicationIdSuffix ".abc" minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 配置测试环境url buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\"" // 要区分渠道的内容 if (mFlavor == "google") { // google渠道测试版百度地图key manifestPlaceholders = [baiduMapKey : "88888888", fileProviderAuthority: "mmmmmmmmm", logo : "R.drawable.logo_google_debug" ] resValue 'string', 'app_name', "我的应用google版_测试包" resValue 'string', 'authority', "mmmmmmmmm" } else { // twitter渠道测试版百度地图key manifestPlaceholders = [baiduMapKey : "99999999", fileProviderAuthority: "nnnnnnnnn", logo : "R.drawable.logo_twitter_debug" ] resValue 'string', 'app_name', "我的应用twitter版_测试包" resValue 'string', 'authority', "nnnnnnnnn" } } }
这里用到了另外两种配置参数的方法,一是manifestPlaceholders,二是resValue。
manifestPlaceholders
可以在 AndroidManifest.xml
中替换参数的值,它接受一个 Map<String, Object>
类型的参数,如以下配置
manifestPlaceholders = [baiduMapKey : "99999999",
logo : "R.drawable.logo_twitter_debug"
]
在 AndroidManifest.xml 文件中用以下方式来取得配置的值:
<!-- 百度地图开发者key -->
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="${baiduMapKey}" />
android:icon="${logo}"
这样,不同渠道取出来的 baiduMapKey
值就不一样了,达到了动态配置的目的
resValue
相当于在 res/values 文件夹下的某个资源文件中增加一个资源,比如在 res/values/strings 中增加一个字符串
resValue 'string', 'app_name', "我的应用twitter版_测试包"
在 xml 文件中就可以引用这个字符串了
android:label="@string/app_name"
这种方式要注意一点:如果原先 strings.xml
文件中已经定义了一个 app_name
的字符串,必须要将这个定义去掉,否则会报资源重复的错误。
还有一点值得注意的是:在 buildType
代码块中怎么判断 flavor
,我借鉴了网上的一种方法,是根据taskName来判断当前编译的代码是属于哪个渠道,不知道有没有更好方式来判断了。
def getFlavor() {
def runTasks = gradle.startParameter.taskNames
def gR = ':app:assembleGoogleRelease'
def gD = ':app:assembleGoogleDebug'
def tR = ':app:assembleTwitterRelease'
def tD = ':app:assembleTwitterDebug'
if (gR in runTasks || gD in runTasks) {
return "google"
}
if (tR in runTasks || tD in runTasks) {
return "twitter"
}
return ""
}
这样,整个配置就完成了,下面把完整的 app下的build.gradle文件中跟渠道配置相关的代码贴出来
android { // 获取渠道名 def mFlavor = getFlavor() compileSdkVersion 28 defaultConfig { minSdkVersion 15 targetSdkVersion 26 // 版本号 versionCode 123 // 版本名 versionName 1.2.3 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true } //配置签名 signingConfigs { google { storeFile file("D:/docs/keyStore/googleKeyStore.jks") storePassword "111111" keyAlias "key0" keyPassword "222222" } twitter { storeFile file("D:/docs/keyStore/twitterKeyStore.jks") storePassword "333333" keyAlias "key1" keyPassword "444444" } } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 配置生产环境url buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\"" // 要区分渠道的内容 if (mFlavor == "google") { // google渠道生产版百度地图key manifestPlaceholders = [baiduMapKey : "11111111111", fileProviderAuthority: "aaaaaaaa", logo : "R.drawable.logo_google_release" ] resValue 'string', 'app_name', "我的应用google版" resValue 'string', 'authority', "aaaaaaaa" } else { // twitter渠道生产版百度地图key manifestPlaceholders = [baiduMapKey : "22222222", fileProviderAuthority: "bbbbbbbbb", logo : "R.drawable.logo_twitter_release", ] resValue 'string', 'app_name', "我的应用twitter版" resValue 'string', 'authority', "bbbbbbbbb" } } debug { // debug包的applicationId在生产包的后面加上后缀".abc" applicationIdSuffix ".abc" minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // 配置测试环境url buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\"" // 要区分渠道的内容 if (mFlavor == "google") { // google渠道测试版百度地图key manifestPlaceholders = [baiduMapKey : "88888888", fileProviderAuthority: "mmmmmmmmm", logo : "R.drawable.logo_google_debug" ] resValue 'string', 'app_name', "我的应用google版_测试包" resValue 'string', 'authority', "mmmmmmmmm" } else { // twitter渠道测试版百度地图key manifestPlaceholders = [baiduMapKey : "99999999", fileProviderAuthority: "nnnnnnnnn", logo : "R.drawable.logo_twitter_debug" ] resValue 'string', 'app_name', "我的应用twitter版_测试包" resValue 'string', 'authority', "nnnnnnnnn" } } } // 定义flavor的dimension,至少要有一个dimension,名字随便取,这个必须要的,不然会报错 flavorDimensions "version" productFlavors { // google渠道 google { applicationId = "com.my.google" signingConfig signingConfigs.google buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_google" buildConfigField "String", "LOGIN_TEXT", "\"请输入google账号\"" } // twitter渠道 twitter { applicationId = "com.my.twitter" signingConfig signingConfigs.twitter buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_twitter" buildConfigField "String", "LOGIN_TEXT", "\"请输入twitter账号\"" } } } def getFlavor() { def runTasks = gradle.startParameter.taskNames def gR = ':app:assembleGoogleRelease' def gD = ':app:assembleGoogleDebug' def tR = ':app:assembleTwitterRelease' def tD = ':app:assembleTwitterDebug' if (gR in runTasks || gD in runTasks) { return "google" } if (tR in runTasks || tD in runTasks) { return "twitter" } return "" }
由于水平有限,如果文中存在错误之处,请大家批评指正,欢迎大家一起来分享、探讨!
博客:http://blog.csdn.net/MingHuang2017
GitHub:https://github.com/MingHuang1024
Email: MingHuang1024@foxmail.com
微信:724360018
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。