概要
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。