增加 启动后延迟更新开关.
使用此开关后,游戏包将在启动进入游戏后才请求更新信息, 直到重启后再打开游戏才应用更新. 优化热更流程,可以在构建完成后,再领奖注入热更,上传更新.
This commit is contained in:
parent
ef915a121e
commit
b81d004641
@ -112,6 +112,9 @@ class FileUploader {
|
||||
this.queue.push({src: i, dst: (remoteStr + i.substring(startIndex)).replace(/\\/g, '/')});
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('待上传文件数量:', this.queue.length);
|
||||
|
||||
this.checkUpload();
|
||||
}
|
||||
|
||||
|
@ -34,21 +34,22 @@ class FileUtil {
|
||||
* @param src
|
||||
* @param dst
|
||||
*/
|
||||
async copy(src, dst) {
|
||||
copy(src, dst) {
|
||||
const st = fs.statSync(src);
|
||||
if (st.isFile()) {
|
||||
const readable = fs.createReadStream(src);//创建读取流
|
||||
const writable = fs.createWriteStream(dst);//创建写入流
|
||||
readable.pipe(writable);
|
||||
const data = fs.readFileSync(src);
|
||||
fs.writeFileSync(dst, data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(dst)) {
|
||||
fs.mkdirSync(dst, {recursive: true});
|
||||
}
|
||||
|
||||
//读取目录
|
||||
const paths = fs.readdirSync(src);
|
||||
for (let path of paths) {
|
||||
this.copy(src + '/' + path, dst + '/' + path);
|
||||
const files = fs.readdirSync(src);
|
||||
for (let p of files) {
|
||||
this.copy(src + path.sep + p, dst + path.sep + p);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,129 +0,0 @@
|
||||
/**
|
||||
* 方便直接获取当前版本号等信息.
|
||||
* 使用方式:
|
||||
* // @ts-ignore
|
||||
* import UpdateManager = require( "UpdateManager");
|
||||
* 然后在代码中直接使用即可.
|
||||
*/
|
||||
class UpdateManager {
|
||||
|
||||
cur_ver_code = 0;
|
||||
cur_ver_name = "1.0.1";
|
||||
cur_ver_desc = "";
|
||||
ver_type = "dev";
|
||||
|
||||
new_ver_code = 0;
|
||||
new_ver_name = "1.0.1";
|
||||
new_ver_desc = "";
|
||||
new_ver_info = {};
|
||||
|
||||
// 记录当前版本的bundles. 如果有新版本, 则自动下载新bundles.
|
||||
cur_bundles = {};
|
||||
|
||||
updateSuccess = "0";
|
||||
|
||||
constructor() {
|
||||
const curVer = window.localStorage.getItem("cur_ver_info");
|
||||
if (curVer) {
|
||||
const verInfo = JSON.parse(curVer);
|
||||
this.new_ver_code = this.cur_ver_code = verInfo.versionCode;
|
||||
this.new_ver_name = this.cur_ver_name = verInfo.versionName;
|
||||
this.ver_type = verInfo.versionType;
|
||||
this.new_ver_desc = this.cur_ver_desc = verInfo.versionLog;
|
||||
this.new_ver_info = verInfo;
|
||||
this.cur_bundles = verInfo.bundleVers;
|
||||
}
|
||||
|
||||
this.updateSuccess = window.localStorage.getItem("ver_updated") || 0;
|
||||
this.fetchNewVerInfo();
|
||||
}
|
||||
|
||||
// 此方法适用于非强制更新包. 需要设计信息界面,显示版本信息.
|
||||
// 手动调用进行更新下载, 下载完成返回true, 此时需要重启游戏才能应用更新. 需要界面提示用户.
|
||||
doUpdate() {
|
||||
if (this.hasNewVersion()) {
|
||||
window.localStorage.setItem('cur_ver_info', JSON.stringify(this.new_ver_info));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
resetUpdateFlag() {
|
||||
window.localStorage.setItem('ver_updated', '0');
|
||||
}
|
||||
|
||||
getUpdateFlag() {
|
||||
return this.updateSuccess == 1;
|
||||
}
|
||||
|
||||
// 检测是否有新版本.
|
||||
hasNewVersion() {
|
||||
return this.new_ver_info && this.new_ver_info.versionCode && this.new_ver_info.versionCode != this.cur_ver_code;
|
||||
}
|
||||
|
||||
fetchNewVerInfo() {
|
||||
let url = window.updateUrl || false;
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
// 游戏启动后再请求更新,避免影响启动速度.
|
||||
url += `?_t=${Math.random()}`;
|
||||
cc.log("请求更新地址:", url);
|
||||
this._get(url).then(version => {
|
||||
if (!version) {
|
||||
console.log("未检测到更新版本内容");
|
||||
return;
|
||||
}
|
||||
if (version) {
|
||||
cc.log('当前版本号:', this.cur_ver_code, this.cur_ver_name);
|
||||
cc.log('请求更新内容:', version);
|
||||
let verInfo = version;
|
||||
if (typeof version === 'string') {
|
||||
verInfo = JSON.parse(version);
|
||||
}
|
||||
this.new_ver_code = verInfo.versionCode;
|
||||
this.new_ver_name = verInfo.versionName;
|
||||
this.new_ver_desc = verInfo.versionLog;
|
||||
|
||||
this.new_ver_info = verInfo;
|
||||
|
||||
// 如果首次运行,本地未缓存版本信息,则进行缓存.
|
||||
if (!this.cur_ver_code) {
|
||||
cc.log("当前首次运行,记录版本信息");
|
||||
window.localStorage.setItem('cur_ver_info', JSON.stringify(this.new_ver_info));
|
||||
|
||||
this.new_ver_code = this.cur_ver_code = verInfo.versionCode;
|
||||
this.new_ver_name = this.cur_ver_name = verInfo.versionName;
|
||||
this.ver_type = verInfo.versionType;
|
||||
this.new_ver_desc = this.cur_ver_desc = verInfo.versionLog;
|
||||
|
||||
} else if (this.hasNewVersion() && verInfo.forceUpdate) {
|
||||
window.localStorage.setItem('cur_ver_info', JSON.stringify(this.new_ver_info));
|
||||
window.localStorage.setItem('ver_updated', '1');
|
||||
cc.log("有新版本,且默认强制更新");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ajax 请求.
|
||||
_get(url) {
|
||||
return new Promise(resolve => {
|
||||
const ajax = new XMLHttpRequest();
|
||||
ajax.open("get", url, true);
|
||||
ajax.setRequestHeader("Content-Type", "application/json;charset=utf-8");
|
||||
ajax.onreadystatechange = function () {
|
||||
if (ajax.readyState == 4) {
|
||||
if (ajax.status == 200) {
|
||||
resolve(ajax.responseText);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
ajax.send(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new UpdateManager();
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "aa7483f4-ac0c-4809-9c5e-4e5734a26db6",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@ -1,35 +1,20 @@
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const {join} = require('path');
|
||||
const path = require('path');
|
||||
const FileUtil = require('./js/FileUtils');
|
||||
const FileUpload = require('./js/FileUploader');
|
||||
const logger = require('./js/logger');
|
||||
|
||||
// 生成更新文件.
|
||||
// 编译完成仅保存每次生成的bundleVers. 之后注入热更阶段再合并.
|
||||
const doMakeUpdatePackage = function (opt, cb) {
|
||||
if (opt.platform == 'android' || opt.platform == 'ios') {
|
||||
try {
|
||||
const configStr = fs.readFileSync(
|
||||
Editor.url('packages://update-manager/.settings.conf'), 'utf-8');
|
||||
const configJson = JSON.parse(configStr || "{}");
|
||||
if (typeof configJson.versionCfg.versionCode === 'undefined') {
|
||||
logger.warn("未配置更新版本,不生成热更Patch");
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
if (!configJson.versionCfg.versionType || configJson.versionCfg.versionType.length <= 0) {
|
||||
configJson.versionCfg.versionType = 'dev';
|
||||
}
|
||||
|
||||
const bundleVers = {};
|
||||
for (let b of opt.bundles) {
|
||||
bundleVers[b.name] = b.version;
|
||||
}
|
||||
saveNewVersionInfo(opt, bundleVers, configJson);
|
||||
|
||||
const remoteDir = join(opt.dest, 'remote');
|
||||
const assetDir = join(opt.dest, 'assets');
|
||||
FileUtil.copy(assetDir, remoteDir);
|
||||
let targetUpdatePath = path.join(opt.dest, `remote/bundleVers.json`);
|
||||
FileUtil.write(targetUpdatePath, JSON.stringify(bundleVers));
|
||||
|
||||
cb && cb();
|
||||
} catch (e) {
|
||||
@ -41,20 +26,44 @@ const doMakeUpdatePackage = function (opt, cb) {
|
||||
}
|
||||
};
|
||||
|
||||
const saveNewVersionInfo = function (opt, bundleVers, configJson) {
|
||||
const getConfigJson = function () {
|
||||
const configStr = fs.readFileSync(
|
||||
Editor.url('packages://update-manager/.settings.conf'), 'utf-8');
|
||||
const configJson = JSON.parse(configStr || "{}");
|
||||
if (typeof configJson.versionCfg.versionCode === 'undefined') {
|
||||
logger.warn("未配置更新版本,不生成热更Patch");
|
||||
return null;
|
||||
}
|
||||
if (!configJson.versionCfg.versionType || configJson.versionCfg.versionType.length <= 0) {
|
||||
configJson.versionCfg.versionType = 'dev';
|
||||
}
|
||||
return configJson;
|
||||
};
|
||||
|
||||
// 注入热更信息.
|
||||
const updateHotFixInfo = function () {
|
||||
const configJson = getConfigJson();
|
||||
if (!configJson) return;
|
||||
|
||||
const bundleVers = path.join(Editor.Project.path, `build/jsb-link/remote/bundleVers.json`);
|
||||
if (!fs.existsSync(bundleVers)) {
|
||||
logger.warn('未找到编译信息,请先构建项目.');
|
||||
return;
|
||||
}
|
||||
const bundles = JSON.parse(fs.readFileSync(bundleVers, 'utf-8'));
|
||||
|
||||
const data = {
|
||||
versionCode: configJson.versionCfg.versionCode,
|
||||
versionName: configJson.versionCfg.versionName,
|
||||
versionType: configJson.versionCfg.versionType,
|
||||
versionLog: configJson.versionCfg.versionLog,
|
||||
forceUpdate: configJson.versionCfg.forceUpdate,
|
||||
server: `${configJson.versionCfg.baseUrl}${configJson.ftpCfg.rootPath}${configJson.versionCfg.versionType}/${configJson.versionCfg.versionCode}`
|
||||
server: `${configJson.versionCfg.baseUrl}${configJson.ftpCfg.rootPath}${configJson.versionCfg.versionType}/${configJson.versionCfg.versionCode}`,
|
||||
bundles: bundles
|
||||
};
|
||||
const updateInfo = Object.assign(data, {bundles: bundleVers});
|
||||
// 将版本更新信息写入文件
|
||||
let targetUpdatePath = join(opt.dest, `remote/update-${configJson.versionCfg.versionType}.json`)
|
||||
FileUtil.write(targetUpdatePath, JSON.stringify(updateInfo, null, 2));
|
||||
logger.log("更新信息存储位置:", targetUpdatePath);
|
||||
|
||||
let targetUpdatePath = path.join(Editor.Project.path, `build/jsb-link/remote/update-${configJson.versionCfg.versionType}.json`);
|
||||
FileUtil.write(targetUpdatePath, JSON.stringify(data, null, 2));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
@ -94,8 +103,17 @@ module.exports = {
|
||||
'open'() {
|
||||
Editor.Panel.open('update-manager');
|
||||
},
|
||||
'saveConfig'() {
|
||||
// 上传更新包前,更新一次热更描述文件.
|
||||
logger.info('生成热更文件...');
|
||||
updateHotFixInfo();
|
||||
logger.info('准备remote 资源...');
|
||||
const remoteDir = path.join(Editor.Project.path, 'build/jsb-link/remote'); // remote 目录.
|
||||
const assetDir = path.join(Editor.Project.path, 'build/jsb-link/assets'); // assets目录.
|
||||
FileUtil.copy(assetDir, remoteDir);
|
||||
logger.info('remote 资源准备完毕,可以开始上传...');
|
||||
},
|
||||
'upload'(event, dir, dst, options) {
|
||||
logger.info('upload....');
|
||||
this.ftp.setOption(options, options.maxThread);
|
||||
this.ftp.upload(dir, dst);
|
||||
},
|
||||
|
@ -9,15 +9,6 @@
|
||||
"message": "update-manager:open"
|
||||
}
|
||||
},
|
||||
"runtime-resource": {
|
||||
"path": "./lib",
|
||||
"name": "lib"
|
||||
},
|
||||
"reload": {
|
||||
"ignore": [
|
||||
"lib/**/*"
|
||||
]
|
||||
},
|
||||
"panel": {
|
||||
"main": "panel/index.html",
|
||||
"type": "simple",
|
||||
|
@ -35,6 +35,13 @@
|
||||
active-color="#13ce66" inactive-color="#ff4949"
|
||||
style="margin-right: 20px;"></el-switch>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">开启时后续更新包将在游戏启动后静默请求更新<br/>否则将在启动时立即请求更新,然后才进入游戏.</div>
|
||||
<el-switch v-model="versionCfg.updateBefore"
|
||||
:active-text="versionCfg.updateBefore?'更新完进游戏':'进游戏后请求更新'"
|
||||
active-color="#13ce66" inactive-color="#ff4949"
|
||||
style="margin-right: 20px;"></el-switch>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-tooltip effect="dark" :content="tip.baseUrl" open-delay=500 placement="top">
|
||||
<el-form-item label="热更地址:">
|
||||
@ -168,7 +175,7 @@
|
||||
|
||||
<el-row style="margin-top: 20px;">
|
||||
<el-col :span="8">
|
||||
<el-button type="success" @click="onSave">保存配置信息</el-button>
|
||||
<el-button type="success" @click="onSave">注入热更配置</el-button>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-button type="danger" @click="onUpload">上传更新包</el-button>
|
||||
@ -201,7 +208,7 @@
|
||||
versionLog: "",
|
||||
baseUrl: "",
|
||||
forceUpdate: true, // 强制静默更新.
|
||||
// updateMoment: true // 启动时直接请求更新.
|
||||
updateBefore: true // 启动时直接请求更新.
|
||||
},
|
||||
ftpCfg: {
|
||||
host: "127.0.0.1",
|
||||
@ -268,9 +275,21 @@
|
||||
this.ftpCfg.rootPath += "/";
|
||||
}
|
||||
const data = Object.assign({}, {versionCfg: this.versionCfg, ftpCfg: this.ftpCfg});
|
||||
fs && fs.writeFileSync && fs.writeFileSync(
|
||||
fs.writeFileSync(
|
||||
Editor.url('packages://update-manager/.settings.conf'), JSON.stringify(data, null, 2), 'utf-8');
|
||||
this.$message({message: "配置保存成功!", type: "success"});
|
||||
|
||||
Editor.Ipc.sendToMain('update-manager:saveConfig');
|
||||
|
||||
let filePath = `update-${this.versionCfg.versionType}.json`;
|
||||
const uploadDstPath = `${this.ftpCfg.rootPath}${this.versionCfg.versionType}/${filePath}`;
|
||||
let updateUrl = `${this.versionCfg.baseUrl}${uploadDstPath}`;
|
||||
const serverUrl = `${this.versionCfg.baseUrl}${this.ftpCfg.rootPath}${this.versionCfg.versionType}/${this.versionCfg.versionCode}`;
|
||||
|
||||
if (this.notifyMainJs(updateUrl, serverUrl, this.versionCfg.updateBefore)) {
|
||||
this.$message.info('热更注入成功');
|
||||
} else {
|
||||
this.$message.error('热更注入失败,请检查构建目录.');
|
||||
}
|
||||
},
|
||||
onUpload() {
|
||||
if (this.uploadState) {
|
||||
@ -280,28 +299,17 @@
|
||||
}
|
||||
this.uploadState = true;
|
||||
|
||||
logger.info("准备上传更新包");
|
||||
this.$message("准备上传更新包");
|
||||
if (!this.versionCfg.baseUrl.endsWith('/') && this.versionCfg.baseUrl.length > 0) {
|
||||
this.versionCfg.baseUrl += "/";
|
||||
}
|
||||
if (!this.ftpCfg.rootPath.endsWith('/') && this.ftpCfg.rootPath.length > 0) {
|
||||
this.ftpCfg.rootPath += "/";
|
||||
}
|
||||
|
||||
let filePath = `update-${this.versionCfg.versionType}.json`;
|
||||
const uploadDstPath = `${this.ftpCfg.rootPath}${this.versionCfg.versionType}/${filePath}`;
|
||||
let updateUrl = `${this.versionCfg.baseUrl}${uploadDstPath}`;
|
||||
const serverUrl = `${this.versionCfg.baseUrl}${this.ftpCfg.rootPath}${this.versionCfg.versionType}/${this.versionCfg.versionCode}`;
|
||||
|
||||
if (!this.notifyMainJs(updateUrl, serverUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ftpCfg.onlyJson) {
|
||||
logger.warn('当前仅上传JSON文件,请手动上传remote目录');
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = `update-${this.versionCfg.versionType}.json`;
|
||||
const uploadDstPath = `${this.ftpCfg.rootPath}${this.versionCfg.versionType}/${filePath}`;
|
||||
logger.info('上传文件:', uploadDstPath);
|
||||
|
||||
// 上传更新描述文件.
|
||||
const updateJsonPath = path.join(this.projectPath, `build/jsb-link/remote/${filePath}`);
|
||||
Editor.Ipc.sendToMain('update-manager:upload', updateJsonPath, uploadDstPath, this.ftpCfg);
|
||||
@ -324,7 +332,7 @@
|
||||
self.uploadState = !args;
|
||||
});
|
||||
},
|
||||
notifyMainJs(updateUrl, serverUrl) {
|
||||
notifyMainJs(updateUrl, serverUrl, updateBefore) {
|
||||
this.$message.info("notifyMainJs");
|
||||
const filePath = path.join(this.projectPath, 'build/jsb-link/main.js');
|
||||
const exists = fs.existsSync(filePath);
|
||||
@ -335,12 +343,13 @@
|
||||
let mainjs = fs.readFileSync(filePath, 'utf-8');
|
||||
let varJs = `window.updateUrl="${updateUrl}";\r\n`;
|
||||
let remoteJs = `window.remoteUrl="${serverUrl}";\r\n`;
|
||||
let updateBeforeFlag = `window.updateBefore=${updateBefore};\r\n`;
|
||||
// preMainJS read.
|
||||
const preMain = fs && fs.readFileSync && fs.readFileSync(
|
||||
Editor.url('packages://update-manager/templates/pre_main.js'), 'utf-8');
|
||||
if (!mainjs.startsWith(varJs)) {
|
||||
mainjs = mainjs.replace('window.boot();', 'window.beforeBoot();');
|
||||
mainjs = varJs + remoteJs + preMain + mainjs;
|
||||
mainjs = varJs + remoteJs + updateBeforeFlag + preMain + mainjs;
|
||||
fs && fs.writeFileSync && fs.writeFileSync(filePath, mainjs, 'utf-8');
|
||||
}
|
||||
this.$message.success("Main.js 热更代码注入成功");
|
||||
|
@ -1,4 +1,5 @@
|
||||
window.beforeBoot = function () {
|
||||
|
||||
// console.log("游戏正在启动中.")
|
||||
if (window.remoteUrl) {
|
||||
const settings = window._CCSettings;
|
||||
@ -11,16 +12,51 @@ window.beforeBoot = function () {
|
||||
window.boot();
|
||||
return;
|
||||
}
|
||||
// 游戏启动后再请求更新,避免影响启动速度.
|
||||
url += `?_t=${Math.random()}`;
|
||||
cc.log("请求更新地址:", url);
|
||||
|
||||
if (window.updateBefore) {
|
||||
_get(url).then(resp => {
|
||||
if (!resp) {
|
||||
window.boot();
|
||||
return;
|
||||
}
|
||||
window.localStorage.setItem('cur_ver_info', resp);
|
||||
window.onBooting();
|
||||
});
|
||||
} else {
|
||||
window.onBooting();
|
||||
_get(url).then(resp => {
|
||||
if (!resp) {
|
||||
return;
|
||||
}
|
||||
window.localStorage.setItem('cur_ver_info', resp);
|
||||
});
|
||||
}
|
||||
};
|
||||
window.onBooting = function () {
|
||||
// 请求缓存信息,判断是否需要更新.
|
||||
let assetStr = window.localStorage.getItem('cur_ver_info');
|
||||
if (!assetStr) {
|
||||
window.boot();
|
||||
} else {
|
||||
// console.log("当前版本信息:", assetStr);
|
||||
console.log("当前版本信息:", assetStr);
|
||||
let asset = JSON.parse(assetStr);
|
||||
window.mergeVersion(asset);
|
||||
window.boot();
|
||||
|
||||
// 判断当前是否有版本更新.
|
||||
const lastVer = window.localStorage.getItem('last_ver_code') || asset.versionCode;
|
||||
const curVer = asset.versionCode || 0;
|
||||
if (lastVer != curVer) {
|
||||
window.localStorage.setItem('new_ver_flag', "1");
|
||||
} else {
|
||||
window.localStorage.setItem('new_ver_flag', "0");
|
||||
}
|
||||
window.localStorage.setItem('last_ver_code', curVer);
|
||||
// 当前版本名称.
|
||||
window.localStorage.setItem('cur_ver_name', asset.versionName);
|
||||
}
|
||||
};
|
||||
window.mergeVersion = function (updateInfo) {
|
||||
@ -41,3 +77,20 @@ window.mergeVersion = function (updateInfo) {
|
||||
}
|
||||
};
|
||||
|
||||
function _get(url) {
|
||||
return new Promise(resolve => {
|
||||
const ajax = new XMLHttpRequest();
|
||||
ajax.open("get", url, true);
|
||||
ajax.setRequestHeader("Content-Type", "application/json;charset=utf-8");
|
||||
ajax.onreadystatechange = function () {
|
||||
if (ajax.readyState == 4) {
|
||||
if (ajax.status == 200) {
|
||||
resolve(ajax.responseText);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
ajax.send(null);
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue
Block a user