diff --git a/packages/update-manager/js/FileUploader.js b/packages/update-manager/js/FileUploader.js index 41ed34e..e332e5a 100644 --- a/packages/update-manager/js/FileUploader.js +++ b/packages/update-manager/js/FileUploader.js @@ -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(); } diff --git a/packages/update-manager/js/FileUtils.js b/packages/update-manager/js/FileUtils.js index 6992f07..c815938 100644 --- a/packages/update-manager/js/FileUtils.js +++ b/packages/update-manager/js/FileUtils.js @@ -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); } }; diff --git a/packages/update-manager/lib/UpdateManager.js b/packages/update-manager/lib/UpdateManager.js deleted file mode 100644 index cb5be34..0000000 --- a/packages/update-manager/lib/UpdateManager.js +++ /dev/null @@ -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(); \ No newline at end of file diff --git a/packages/update-manager/lib/UpdateManager.js.meta b/packages/update-manager/lib/UpdateManager.js.meta deleted file mode 100644 index 7104b18..0000000 --- a/packages/update-manager/lib/UpdateManager.js.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.0.8", - "uuid": "aa7483f4-ac0c-4809-9c5e-4e5734a26db6", - "isPlugin": false, - "loadPluginInWeb": true, - "loadPluginInNative": true, - "loadPluginInEditor": false, - "subMetas": {} -} \ No newline at end of file diff --git a/packages/update-manager/main.js b/packages/update-manager/main.js index b0c3d9c..6023d7f 100644 --- a/packages/update-manager/main.js +++ b/packages/update-manager/main.js @@ -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); }, diff --git a/packages/update-manager/package.json b/packages/update-manager/package.json index 88d56e3..5e13ce5 100644 --- a/packages/update-manager/package.json +++ b/packages/update-manager/package.json @@ -9,15 +9,6 @@ "message": "update-manager:open" } }, - "runtime-resource": { - "path": "./lib", - "name": "lib" - }, - "reload": { - "ignore": [ - "lib/**/*" - ] - }, "panel": { "main": "panel/index.html", "type": "simple", diff --git a/packages/update-manager/panel/index.html b/packages/update-manager/panel/index.html index be79522..534c216 100644 --- a/packages/update-manager/panel/index.html +++ b/packages/update-manager/panel/index.html @@ -35,6 +35,13 @@ active-color="#13ce66" inactive-color="#ff4949" style="margin-right: 20px;"> + + 开启时后续更新包将在游戏启动后静默请求更新否则将在启动时立即请求更新,然后才进入游戏. + + @@ -168,7 +175,7 @@ - 保存配置信息 + 注入热更配置 上传更新包 @@ -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 热更代码注入成功"); diff --git a/packages/update-manager/templates/pre_main.js b/packages/update-manager/templates/pre_main.js index 83cdce6..2aff676 100644 --- a/packages/update-manager/templates/pre_main.js +++ b/packages/update-manager/templates/pre_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); + }); +}; \ No newline at end of file