一、為什麼使用美團多渠道打包的方式?
- 打包更加快速 傳統的通過productFlavors渠道包的方式,渠道10個以內還可以接受,如果100個渠道包,每個包需要打5Min,就是將近10個小時的打包,而採用美團Walle多渠道打包的方式只需要打一個包的時間。
- 配置更加靈活 可以在APK渠道包中通過配置config檔案,針對於不同渠道包配置各個渠道定製化額外資訊
二、多渠道打包原理介紹
整個APK(ZIP檔案格式)會被分為以下四個區塊:
- Contents of ZIP entries(from offset 0 until the start of APK Signing Block)
- APK Signing Block
- ZIP Central Directory
- ZIP End of Central Directory
這個是V2簽名包的APK包格式,新的應用簽名方案有著良好的向後相容性,能完全相容低於Android 7.0(Nougat)的版本。對比舊簽名方案,它有更快的驗證速度和更安全的保護。 區塊1、3、4都是受保護區塊,不允許修改保護區塊。美團打包的方式,是在2區塊內寫入ID-value的擴充套件資訊(渠道資訊),並儲存到APK中。這樣,每打一個渠道包只需複製一個APK,然後在APK中新增一個ID-value即可,這種打包方式速度非常快,對一個30M大小的APK包只需要100多毫秒(包含檔案複製時間)就能生成一個渠道包,而在執行時獲取渠道資訊只需要大約幾毫秒的時間。
三、Walle的工程配置及打包方式
在位於專案的根目錄 build.gradle 檔案中新增Walle Gradle外掛的依賴, 如下:
buildscript {
dependencies {
classpath 'com.meituan.android.walle:plugin:1.1.6'
}
}
複製程式碼
並在當前App的 build.gradle 檔案中apply這個外掛,並新增上用於讀取渠道號的AAR
apply plugin: 'walle'
dependencies {
compile 'com.meituan.android.walle:library:1.1.6'
}
複製程式碼
配置外掛
walle {
// 指定渠道包的輸出路徑
apkOutputFolder = new File("${project.buildDir}/outputs/channels");
// 定製渠道包的APK的檔名稱
apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk';
// 渠道配置檔案
channelFile = new File("${project.getProjectDir()}/channel")
}
複製程式碼
配置項具體解釋:
- apkOutputFolder:指定渠道包的輸出路徑, 預設值為
new File("${project.buildDir}/outputs/apk")
- apkFileNameFormat:定製渠道包的APK的檔名稱, 預設值為
${appName}-${buildType}-${channel}.apk
可使用以下變數:
projectName - 專案名字
appName - App模組名字
packageName - applicationId (App包名packageName)
buildType - buildType (release/debug等)
channel - channel名稱 (對應渠道打包中的渠道名字)
versionName - versionName (顯示用的版本號)
versionCode - versionCode (內部版本號)
buildTime - buildTime (編譯構建日期時間)
fileSHA1 - fileSHA1 (最終APK檔案的SHA1雜湊值)
flavorName - 編譯構建 productFlavors 名
複製程式碼
插入額外資訊 channelFile只支援渠道寫入,如果想插入除渠道以外的其他資訊,請在walle配置中使用configFile
walle {
// 渠道&額外資訊配置檔案,與channelFile互斥
configFile = new File("${project.getProjectDir()}/config.json")
}
複製程式碼
configFile是包含渠道資訊和額外資訊的配置檔案路徑。 配置檔案採用json格式,支援為每個channel單獨配置額外的寫入資訊。
{
//extraInfo 不要出現以`channel`為key的情況
/*
不宣告extraInfo的channel預設使用的extraInfo
如果沒有此項則沒有預設extraInfo
*/
"defaultExtraInfo": {
"key2": "20161213",
"key": "20161212"
},
/*
strategy:
1. ifNone (預設適用此策略) : 僅當對應channel沒有extraInfo時生效
2. always : 所有channel都生效,channel中extraInfo的key與defaultExtraInfo重複時,覆蓋defaultExtraInfo中的內容。
*/
//"defaultExtraInfoStrategy": "always",
"channelInfoList": [
{
"channel": "meituan",
// 此channel將使用自己宣告的extraInfo
/*
此alias可以做到寫入apk的channel是meituan,而打包時輸出的檔名是美團
注意:alias不宣告時,walle配置apkFileNameFormat中channel就是channel,否則為alias
*/
"alias": "美團",
"extraInfo": {
"buildtime": "20161212",
"hash": "123"
}
},
{
"channel": "360cn",
// 此channel將使用自己宣告的extraInfo
"extraInfo": {
"key": "20161213"
}
},
{
"channel": "googleplay"
// 此channel將使用defaultExtraInfo
},
{
"channel": "xiaomi"
// 此channel將使用defaultExtraInfo
},
{
"channel": "meizu"
// 此channel將使用defaultExtraInfo
},
{
"channel": "wandoujia",
"excludeDefaultExtraInfo": true
//強制宣告不使用defaultExtraInfo,預設false
},
{
"channel": "myapp",
"excludeDefaultExtraInfo": true,
//強制宣告不使用defaultExtraInfo,預設false
"extraInfo": {
// 儘管exclude default,但也可以繼續寫入自己的。
"key": "20161212"
}
}
]
}
複製程式碼
注意:
- 此配置項與channelFile功能互斥,開發者在使用時選擇其一即可,兩者都存在時configFile優先執行。
- extraInfo 不要出現以channel為key的情況
如何獲取渠道資訊:
在需要渠道等資訊時可以通過下面程式碼進行獲取
String channel = WalleChannelReader.getChannel(this.getApplicationContext());
複製程式碼
生成渠道包
AS右側點開Gradle工具欄,如下圖所示,雙擊執行Task任務
生成的APK渠道包,根據Walle配置檔案路徑查詢
四、關於友盟統計多渠道的變更
因為友盟統計之前的多渠道統計方式是在AndroidManifast.xml檔案中配合Gradle指令碼productFlavors實現的多渠道資訊整合。採用這種多渠道打包方式之後,productFlavors不存在了,就算沒有刪除通過原有的獲取渠道資訊的方式獲取到的渠道資訊也不對了。所以需要進行變更。很簡單,只需在友盟初始化的時候把Channel資訊作為引數傳入即可。如下所示:
/**
* 作者:郭翰林
* 時間:2018/6/15 0015 12:07
* 註釋:Umeng初始化配置
*
* @param mAppContext
* @param mUmengKey
* @param mUmengChannel
* @param mUmengSecret
*/
public UmengModule(Context mAppContext, String mUmengKey, String mUmengChannel, String mUmengSecret) {
this.mUmengKey = mUmengKey;
this.mUmengChannel = mUmengChannel;
this.mUmengSecret = mUmengSecret;
this.mAppContext=mAppContext;
UMConfigure.init(mAppContext, mUmengKey, mUmengChannel, UMConfigure.DEVICE_TYPE_PHONE, mUmengSecret);
}
/**
* 作者:郭翰林
* 時間:2018/6/15 0015 14:15
* 註釋:註冊友盟,不要做主程式判斷和線上程裡註冊
*/
private void registerUmeng() {
UmengModule module = new UmengModule(sysApplication, "XXXXXXXXXXX",
WalleChannelReader.getChannel(sysApplication), "XXXXXXXXXX");
.........
.........
}
複製程式碼