Android多渠道打包配置
之前为了在同一台手机能同时安装测试包和生产包,采用配置buildType的方式来实现,相比于flavor,感觉是挺轻量又恰到好处的配置,具体见通过配置applicationId来实现测试包和生产包安装在同一台手机上。最近因为业务需要,需要多个渠道的包了,这就必须要用到flavor这个大杀器了。一路配置下来,感觉还挺顺,下面就具体记录一下。
目标
先说一下需求,增加一个渠道
- 功能代码几乎完全相同,个别接口要根据渠道传参
- logo要按渠道配置
- 应用程序的名子也要不同
- 部分页面的标识性图片要按渠道配置
大概就是这么些东西需要根据渠道来配置的。不过还有一些潜在的东西也需要按渠道来配置,如:
- applicationId,肯定是要不同的
- 签名肯定是区分的
- 百度地图的key也必须要根据渠道配置的,以及其它类似的三方鉴权相关配置
- 自动升级时安装app所需要的fileProviderAuthority也要区分
由于我还保留着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
}
}
- 注意一点,signingConfigs{…}代码块要放在引用它的代码之前,否则会找不到引用的签名
三、 配置只需要区分渠道而不需要区分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