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: [email protected]
微信:724360018