概要
cordova-hot-code-push-plugin(以下簡稱chcp)本身已經支持自動檢查更新、下載、安裝,具體內容可以搜索“cordova熱更新”,或查看官方wiki。本文主要介紹如何使用chcp提供的JS API控制整個熱更新過程,包括其中一些注意事項。本文僅針對安卓,iOS暫未驗證。
需求背景
- 顯示更新內容(彈窗)
- 可手動檢查更新(點擊按鈕)
存在的問題
chcp提供的API基本能滿足大部分功能,但為了滿足需求還需要解決以下問題:
- 官方沒有提供顯示更新內容的方法
- 檢查更新時,如果有更新,會等到下載完成才執行回調函數,導致操作長時間沒有反饋;另一方面,如果有error(正在更新等),回調函數又會立即執行
思路
針對問題1:在配置文件chcp.json中新增字段表示更新內容,並通過直接請求或調用API獲取,比如"message":"1. bug修復...",並在具體流程中展示彈窗(本文是在更新內容下載完成後,也可以在檢查到有更新的時候)
針對問題2:單獨請求服務端的chcp.json,並跟本地的版本比較,不同就認為有更新,可以立即反饋給用户
API驗證
getVersionInfo((err, data) => {...}) 獲取版本信息
data.currentWebVersion 對應www/chcp.json中的release,本地配置,就是比較版本要用到的
data.readyToInstallWebVersion 本次要安裝的版本,為空可能是沒有獲取到服務端配置,或者已是最新版
data.previousWebVersion 更新後的上一個版本,為空説明還沒有更新過
data.appVersion 版本號,對應config.xml中的widget的version,本地配置
data.buildVersion 構建版本號,本地配置
實際測試,只要服務端的release字段和本地的currentWebVersion不同,chcp就認為需要更新,而不會檢查appVersion或者buildVersion是否相同(chcp.json中也沒有這兩個字段)。
fetchUpdate((err, data) => {...}, options) 獲取更新
如果有更新,fetchUpdate只有在下載完成所有更新後才執行回調函數。如果正在下載更新,回調函數會立即執行,err.code為-17。為了區分上述兩種情況且只有一次提示,首次檢查到有更新時,提示可以使用setTimeout延時,回調函數執行時,先clearTimeout,再執行有error時的提示。
需要注意的是,下載成功後,回調函數中data的內容如下:
{
config: '"release":"xxx",...'
}
其實就是把chcp.json的內容作為字符串作為config屬性的值。如果要獲取裏面的值,需要做一次JSON解析。
isUpdateAvailableForInstallation((err, data) => {...}) 檢查本地是否有可供安裝的更新
如果沒有調用過fetchUpdate,或者已經是最新版,則error存在,表示沒有可以安裝的更新,需要獲取更新,具體參見官方示例。
installUpdate((err) => {...}) 執行安裝
整體流程
- 比較本地和服務端版本,版本不同 -> 2
- 檢查本地是否有可安裝的更新,沒有 -> 3,有 -> 4
- 從服務端下載更新,會有以下幾種情況:
a. 沒有更新(一般不會出現,除非1到3之間,server版本回退了...)
b. 正在下載更新中(沒下載完成的時候,點擊“檢查更新”)
c. 不能使用熱更新,需要更新包(原生代碼有修改的時候,熱更新已經不能向後兼容)
d. 其他錯誤
e. 正常下載完成 -> 4 - 彈窗顯示更新內容,用户點擊“立即體驗”後,安裝更新,安裝成後會直接刷新,目測是跳轉到index
另外,最好將自動下載和自動安裝關閉,防止衝突:
config.xml
<chcp>
<auto-download enabled="false" />
<auto-install enabled="false" />
</chcp>
具體代碼
// 獲取本地的currentWebVersion,並和服務端的release比較
function compareVersion(serverVersion) {
return new Promise((resolve, reject) => {
window.chcp.getVersionInfo((error, data) => {
console.log('getVersionInfo', data);
if (error) {
reject(error)
} else {
resolve(data.currentWebVersion === serverVersion);
}
});
});
}
// 請求服務端chcp.json
function checkUpdate() {
const url = "https://yourserver/chcp.json";
fetch(url).then(res => res.json()).then(data => compareVersion(data.release)).then(isEqual => {
if (isEqual) {
toast('已是最新版');
} else {
// 流程2,檢查是否有可安裝更新
checkAvalilable();
}
}).catch((error) => {
console.log('checkUpdate failed', error)
});
}
// 檢查是否有可安裝的更新
function checkAvalilable() {
console.log('checkAvalilable');
window.chcp.isUpdateAvailableForInstallation((error, data) => {
if (error) {
console.log('isUpdateAvailableForInstallation error', error);
checkHotUpdate();
return;
}
// 已有可安裝版本
beforeInstallAlert();
});
}
// 獲取更新
function checkHotUpdate() {
console.log('checkHotUpdate');
const waitingId = setTimeout(() => {
toast('有新版,開始更新');
}, 200);
window.chcp.fetchUpdate((error, data) => {
if (error) {
console.log('fetchUpdate error', error);
clearTimeout(waitingId);
if (error.code == 2) {
toast('已是最新版');
} else if (error.code == -17) {
toast('正在下載更新中...');
} else if (error.code == -2) {
// 需要下載apk
} else {
toast(`出錯了: ${error.code}`);
}
return;
}
// 服務器版本信息
console.log('fetchUpdate data', data);
// JSON解析config
const config = data && data.config && JSON.parse(data.config);
console.log('fetchUpdate config', config);
// 下載完成,message為自定義字段,表示更新內容
beforeInstallAlert(config && config.message);
});
}
function beforeInstallAlert(message) {
// 彈窗邏輯,點擊“立即體驗”調用installUpdate()
}
function installUpdate() {
console.log('installUpdate');
window.chcp.installUpdate((error) => {
if (error) {
console.log('installUpdate error', error);
toast(`安裝失敗: ${error.code}`);
return;
}
console.log('installUpdate done');
});
}
其他
err.code參見Error codes