不说话,装高手。
Maintain silence and pretend to be an experta
// 添加插件
cordova plugin add cordova-hot-code-push-plugin
// 全局安装热更新工具
npm或cnpm install -g cordova-hot-code-push-cli
// 在cordova根目录上执行命令添加cordova-hcp.json文件,该文件是热更新文件chcp.json的模版
cordova-hcp init
Running init
Please provide: Enter project name (required): cordovaVueDemo // 项目名称
Please provide: Amazon S3 Bucket name (required for cordova-hcp deploy): // 亚马逊S3储存桶名字,可以跳过
Please provide: Path in S3 bucket (optional for cordova-hcp deploy): // S3储存桶路径,可以跳过
Please provide: Amazon S3 region (required for cordova-hcp deploy): (us-east-1) // 亚马逊S3地区,可以跳过
Please provide: IOS app identifier: // IOS应用程序商店的应用程序ID。App升级是跳转应用商店进行升级
Please provide: Android app identifier: // Android App在应用商城的地址,或者App的下载地址
Please provide: Update method (required): (resume) start // 执行更新的方法 start(启动应用程序时) resume(恢复应用程序时,比如从控制台切换到前景) now(下载完更新立即安装)
Please provide: Enter full URL to directory where cordova-hcp build result will be uploaded: http://xxxxxx.com/www // www资源文件在服务器上的地址
Project initialized and cordova-hcp.json file created.
If you wish to exclude files from being published, specify them in .chcpignore
Before you can push updates you need to run "cordova-hcp login" in project directory
// 另外生成cordova-hcp.json文件后还需要在文件中添加"autogenerated": true
// 如果不添加更新将无效,操作完成后完整的cordova-hcp.json文件应该是这样
// 添加iosMinVersion、androidVersion以控制App版本,插件更新需要重装app才能生效
{
"name": "cordovaVueDemo", // 可为空
"autogenerated": true, // 如果不添加,热更新会不能使用
"ios_identifier": "", // 应用在App store id(可为空)
"android_identifier": "", // 应用在应用商城上的地址或者App的下载地址(可为空)
"update": "start", // 在应用启动时安装
"content_url": "http://xxxxxx/cordova/www", // www文件在服务器上的地址
"iosMinVersion": "1.0.0", // ios版本,通过这个判断是否需要重新下载app,一般是更新了cordova插件才需要改变这个
"androidVersion": "1.0.0" // android版本,通过这个判断是否需要重新下载app,一般是更新了cordova插件才需要改变这个
"updateLog": "更新日志"
}
chcp.json 包含cordova-hcp.json模版中的信息、最新发布信息、资源时间、native side版本号
chcp.mainfest 包含热更新静态文件信息(资源文件名和对应的hash值,更新的时候会通过对应的hash值来匹配对应的文件达到精确更新)
// 执行命令
cordova-hcp build
// 执行完命令会在模版当中添加"release":"当前时间"字段,我们判断更新时就是通过这个字段进行判断
"release": "2021.06.17-16.30.20", // 唯一web项目版本号,用与热更新web内容的更新。(必需)
// 在config.xml下方找个位置添加
<chcp>
<config-file url="http://xxxxxx/cordova/www/chcp.json" /> // 配置文件 chcp.json 从服务器上加载的路径(必须的配置项)
<auto-download enabled="false" /> // 是否自动下载更新,默认为true,因为我是通过方法手动更新的,所以设置为false
<auto-install enabled="false" /> // 是否自动安装更新,默认为true,因为我是通过方法手动更新的,所以设置为false
<native-interface version="1" /> // 当前 native side 的版本号
</chcp>
在这一步直接将www文件夹里的文件替换服务器上的,需要注意的是www文件在服务地地址一定要与"content_url":"http://************/cordova/www"
和config.xml中<config-file url="https://************/cordova/www/chcp.json" />
填写的地址一致,这是后重启App,热更新就应该能正常执行,但是我们将"auto-download" 和 "auto-install"设置为false,所以更新不会自动执行,所以我们接下来就要编写更新逻辑
// 我使用的是vue项目,所以我的写法就按照vue的来
// 创建util.js文件
class Util {
// 配置热更新服务地址
chcpConfigure() {
return new Promise((resolve, reject) => {
chcp.configure(
{ "config-file": process.env.VUE_APP_CHCP_SERVER },
(err) => {
if (err) {
Toast("热更新地址配置出错");
reject();
} else {
resolve();
}
}
);
});
}
// 获取热更新版本号
chcpGetVersion() {
return new Promise((resolve, reject) => {
chcp.getVersionInfo((err, data) => {
if (err) {
reject();
} else {
resolve(data);
}
});
});
}
// 检查服务器是否存在更新
chcpFetchUpdate() {
return new Promise((resolve, reject) => {
chcp.fetchUpdate((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
// 安装已下载更新
chcpInstallUpdate() {
return new Promise((resolve, reject) => {
chcp.installUpdate(err => {
if (err) {
reject(err)
} else {
resolve()
}
});
})
}
}
export default new Util();
// 在App.vue文件中编写逻辑
import util from "@/common/util";
export default {
methods: {
getAppChcpVersion() {
util.chcpGetVersion().then((versionData) => {
this.checkedAppUpdate(versionData, 0);
});
},
checkedAppUpdate(versionData, type) {
// type 0 自动检测 1 手动更新
const self = this;
// getOnlineVersion 函数是直接用axios.get方法请求线上服务器www的chcp.json文件,获取到里面的数据,用来对比
getOnlineVersion().then((res) => {
let iosMinVersion = Number(res.iosMinVersion.replace(/\./g, "")),
androidVersion = Number(res.androidVersion.replace(/\./g, "")),
appVersion = Number(versionData.appVersion.replace(/\./g, ""));
// 判断允许增量还是必须下载完整App
if (
(util.isAndroid() && appVersion < androidVersion) ||
(util.isIos() && appVersion < iosMinVersion)
) {
self.$dialog
.alert({
title: "标题",
message: "请前往并下载完整App",
theme: "round-button",
})
.then(() => {
window.location.href = "app下载地址";
});
} else {
if (versionData.currentWebVersion != res.release) {
// 判断是否强制更新
if (res.updateType == 1) {
self.$toast({
message: "系统强制更新!!!",
onClose() {
self.checkedHasFetchUpdate();
},
});
} else {
self.$dialog
.confirm({
title: "软件更新",
message: res.updateLog,
})
.then(() => {
self.checkedHasFetchUpdate();
})
.catch(() => {});
}
}
}
});
},
checkedHasFetchUpdate() {
this.$toast.loading({
message: "更新中...",
duration: 0,
});
util
.chcpFetchUpdate()
.then((data) => {
util
.chcpInstallUpdate()
.then(() => {
this.$toast("成功安装更新");
})
.catch((err) => {
console.log(err);
this.$toast("更新安装出错");
});
})
.catch((err) => {
console.log(err);
this.$toast("更新包获取失败");
});
},
},
created(){
document.addEventListener(
"deviceready",
() => {
this.getAppChcpVersion();
},
false
);
}
}
// 如果没问题的话到了这一步热更新就能正常执行,打开App时就会执行方法,有更新的话就会弹出提示要求更新
方法名称 | 回调参数 | 说明 |
---|---|---|
chcp.isUpdateAvailableForInstallation | (error, data) | 判断是否存在已下载完成的更新可用于安装 |
chcp.fetchUpdate | (error, data) | 获取服务器版本状态,如存在更新,则下载更新文件 |
chcp.installUpdate | (error) | 安装已下载的更新 |
事件名称 | 说明 |
---|---|
chcp_updateIsReadyToInstall | 新版本成功下载,准备更新 |
chcp_updateLoadFailed | 插件无法从服务器中获取更新数据 |
chcp_nothingToUpdate | 插件从成功服务器中获取更新数据配置,但不存在新版本 |
chcp_beforeInstall | 更新安装前 |
chcp_updateInstalled | 更新成功安装后 |
chcp_updateInstallFailed | 安装更新出错 |
chcp_nothingToInstall | 未安装任何更新;可能是未先下载更新内容 |
chcp_beforeAssetsInstalledOnExternalStorage | 插件准备下载更新内容到存储中 |
chcp_assetsInstalledOnExternalStorage | 插件成功下载更新内容到存储中 |
chcp_assetsInstallationError | 插件下载更新内容出错;可能是因为存储空间不足等原因 |
错误代码 | 错误名称 | 说明 |
---|---|---|
1 | NOTHING_TO_INSTALL | 发送了安装更新的请求,但未找到任何更新内容 |
2 | NOTHING_TO_UPDATE | 不存在更新内容 |
-1 | FAILED_TO_DOWNLOAD_APPLICATION_CONFIG | 无法从服务器中下载更新配置文件;可能是配置文件不存在或存在网络问题 |
-2 | APPLICATION_BUILD_VERSION_TOO_LOW | 客户端版本低于更新要求;需重新下载新版本的APK或IPA |
-3 | FAILED_TO_DOWNLOAD_CONTENT_MANIFEST | 下载更新内容校验文件出错;可能是content_url配置错误导致 |
-4 | FAILED_TO_DOWNLOAD_UPDATE_FILES | 检查chcp.manifest,里面罗列的所有文件必须放在服务器对应位置,而且每个文件的校验值必须和chcp.manifest里面的一致 |
-5 | FAILED_TO_MOVE_LOADED_FILES_TO_INSTALLATION_FOLDER | 移动下载的更新文件到安装目录时出错,可能是因为设备空间不足 |
-6 | UPDATE_IS_INVALID | 下载的更新包无效;可能是因为下载的文件和chcp.manifest里面的校验值不一致导致的 |
-7 | FAILED_TO_COPY_FILES_FROM_PREVIOUS_RELEASE | 从旧版本中拷贝www目录到新版本目录时出错,可能是因为设备空间不足 |
-8 | FAILED_TO_COPY_NEW_CONTENT_FILES | 复制新文件到安装目录出错,可能是因为设备空间不足 |
-9 | LOCAL_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND | 从存储空间读取配置文件时出错;可能是因为配置文件被手动删除了;插件将读取上次配置 |
-10 | LOCAL_VERSION_OF_MANIFEST_NOT_FOUND | 从存储空间读取校验文件时出错;可能是因为校验文件被手动删除了;插件将读取上次配置 |
-11 | LOADED_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND | 读取新版本的配置文件出错;发生在安装更新过程中;可能原因是用户手动删除了该文件;该文件夹将在下次App运行时还原 |
-12 | LOADED_VERSION_OF_MANIFEST_NOT_FOUND | 读取新版本的校验文件出错;发生在安装更新过程中;可能原因是用户手动删除了该文件;该文件夹将在下次App运行时还原 |
-13 | FAILED_TO_INSTALL_ASSETS_ON_EXTERNAL_STORAGE | 从安装目录复制www文件夹到存储卡时出错;可能是因为存储空间不足;发生在应用第一次启动的时候;该错误将导致插件无法正常工作 |
-14 | CANT_INSTALL_WHILE_DOWNLOAD_IN_PROGRESS | 在下载的过程中调用了安装更新的命令;必须得等下载完成后才可以调用安装命令 |
-15 | CANT_DOWNLOAD_UPDATE_WHILE_INSTALLATION_IN_PROGRESS | 在安装的过程中调用了下载更新的命令;必须得等安装完成后才可以调用下载命令 |
-16 | INSTALLATION_ALREADY_IN_PROGRESS | 在安装过程中又再次调用了安装命令 |
-17 | DOWNLOAD_ALREADY_IN_PROGRESS | 在下载过程中又再次调用了下载命令 |
-18 | ASSETS_FOLDER_IN_NOT_YET_INSTALLED | 在应用第一次启动的时候,插件正在复制www文件到存储空间的时候,调用了chcp 热更新的方法 |