1、下载version_generator.js 文件
,放入下面目录中
或者直接贴代码
/**
* 此模块用于热更新工程清单文件的生成
*/
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');
var manifest = {
//服务器上资源文件存放路径(src,res的路径)
// packageUrl: 'http://xxxx:8080/hotupdate/',
// //服务器上project.manifest路径
// remoteManifestUrl: 'http://xxxx:8080/hotupdate/project.manifest',
// //服务器上version.manifest路径
// remoteVersionUrl: 'http://xxxx:8080/hotupdate/version.manifest',
version: '1.0.0',
assets: {},
searchPaths: []
};
//生成的manifest文件存放目录
var dest = 'assets/';
//项目构建后资源的目录
var src = 'build/jsb-link/';
/**
* node version_generator.js -v 1.0.0 -u http://your-server-address/tutorial-hot-update/remote-assets/ -s native/package/ -d assets/
*/
// Parse arguments
var i = 2;
while ( i < process.argv.length) {
var arg = process.argv[I];
switch (arg) {
case '--url' :
case '-u' :
var url = process.argv[i+1];
manifest.packageUrl = url;
manifest.remoteManifestUrl = url + 'project.manifest';
manifest.remoteVersionUrl = url + 'version.manifest';
i += 2;
break;
case '--version' :
case '-v' :
manifest.version = process.argv[i+1];
i += 2;
break;
case '--src' :
case '-s' :
src = process.argv[i+1];
i += 2;
break;
case '--dest' :
case '-d' :
dest = process.argv[i+1];
i += 2;
break;
default :
I++;
break;
}
}
function readDir (dir, obj) {
var stat = fs.statSync(dir);
if (!stat.isDirectory()) {
return;
}
var subpaths = fs.readdirSync(dir), subpath, size, md5, compressed, relative;
for (var i = 0; i < subpaths.length; ++i) {
if (subpaths[i][0] === '.') {
continue;
}
subpath = path.join(dir, subpaths[I]);
stat = fs.statSync(subpath);
if (stat.isDirectory()) {
readDir(subpath, obj);
}
else if (stat.isFile()) {
// Size in Bytes
size = stat['size'];
md5 = crypto.createHash('md5').update(fs.readFileSync(subpath, 'binary')).digest('hex');
compressed = path.extname(subpath).toLowerCase() === '.zip';
relative = path.relative(src, subpath);
relative = relative.replace(/\\/g, '/');
relative = encodeURI(relative);
obj[relative] = {
'size' : size,
'md5' : md5
};
if (compressed) {
obj[relative].compressed = true;
}
}
}
}
var mkdirSync = function (path) {
try {
fs.mkdirSync(path);
} catch(e) {
if ( e.code != 'EEXIST' ) throw e;
}
}
// Iterate res and src folder
readDir(path.join(src, 'src'), manifest.assets);
readDir(path.join(src, 'res'), manifest.assets);
var destManifest = path.join(dest, 'project.manifest');
var destVersion = path.join(dest, 'version.manifest');
mkdirSync(dest);
fs.writeFile(destManifest, JSON.stringify(manifest), (err) => {
if (err) throw err;
console.log('Manifest successfully generated');
});
delete manifest.assets;
delete manifest.searchPaths;
fs.writeFile(destVersion, JSON.stringify(manifest), (err) => {
if (err) throw err;
console.log('Version successfully generated');
});
2、Hotupdate脚本
cc.Class({
extends: cc.Component,
properties: {
manifestUrl: {
default: null,
url: cc.RawAsset //这里指向生成的project.manifest文件
},
tip: cc.Label, //这里都是标识更新进度的 可以删除相关代码
file: cc.Label,
progress: cc.Label,
filePath: cc.Label,
labelMsg:cc.Label,
},
enterGame: function () {
cc.director.loadScene("Login");
},
checkCb: function (event) {
cc.log('Code: ' + event.getEventCode());
console.log('Code: ' + event.getEventCode());
switch (event.getEventCode())
{
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
cc.log("No local manifest file found, hot update skipped.");
// this.tip.getComponent(cc.Label).string = "没有本地manifest文件,跳过更新";
cc.eventManager.removeListener(this._checkListener);
console.log('code1==' , event.getEventCode());
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
cc.log("Fail to download manifest file, hot update skipped.");
// this.tip.getComponent(cc.Label).string = "下载manifest文件失败,跳过更新";
cc.eventManager.removeListener(this._checkListener);
console.log('code2==' , event.getEventCode());
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
cc.log("Already up to date with the latest remote version.");
// this.tip.getComponent(cc.Label).string = "已经是最新版本,无需更新";
cc.eventManager.removeListener(this._checkListener);
console.log('code3==' , event.getEventCode());
this.enterGame();
break;
case jsb.EventAssetsManager.NEW_VERSION_FOUND:
cc.log("New version found start update ");
// this.tip.getComponent(cc.Label).string = "发现新版本准备更新";
this._needUpdate = true;
cc.eventManager.removeListener(this._checkListener);
console.log('code4==' , event.getEventCode());
this.hotUpdate();
break;
default:
break;
}
},
updateCb: function (event) {
var needRestart = false;
var failed = false;
console.log('start__________________________________updateCb' );
switch (event.getEventCode())
{
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
cc.log('No local manifest file found, hot update skipped.');
console.log('No local manifest file found, hot update skipped.');
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
// this.tip.getComponent(cc.Label).string = "正在更新";
cc.log( event.getDownloadedFiles() + ' / ' + event.getTotalFiles());
cc.log( event.getDownloadedBytes() + ' / ' + event.getTotalBytes());
var percent = event.getPercent();
var percentByFile = event.getPercentByFile();
// this.file.getComponent(cc.Label).string = "下载文件数: " + event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
var msg = event.getMessage();
console.log('UPDATE_PROGRESSION==' , event.getEventCode());
if (msg) {
cc.log(msg);
}
// this.labelMsg.getComponent(cc.Label).string = "文件进度:" + percent.toFixed(2) * 100 + "%"
cc.log(percent.toFixed(2)* 100 + '%');
console.log(percent.toFixed(2)* 100 + '%');
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
cc.log('Fail to download manifest file, hot update skipped.');
// this.tip.getComponent(cc.Label).string = "下载失败";
failed = true;
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
cc.log('Already up to date with the latest remote version.');
console.log('Already up to date with the latest remote version.');
// this.tip.getComponent(cc.Label).string = "已经是最新版本";
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_FINISHED:
cc.log('Update finished. ' + event.getMessage());
console.log('更新完成:正在重启游戏');
// this.tip.getComponent(cc.Label).string = "更新完成:正在重启游戏";
needRestart = true;
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
cc.log('Update failed. ' + event.getMessage());
console.log('Update failed. ' + event.getMessage());
this._failCount ++;
if (this._failCount < 5)
{
this._am.downloadFailedAssets();
}
else
{
cc.log('Reach maximum fail count, exit update process');
this._failCount = 0;
failed = true;
}
break;
case jsb.EventAssetsManager.ERROR_UPDATING:
cc.log('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage());
console.log('Asset update error: ' + event.getAssetId() + ', ' + event.getMessage());
break;
case jsb.EventAssetsManager.ERROR_DECOMPRESS:
cc.log(event.getMessage());
console.log('Update failed. ' + event.getMessage());
break;
default:
break;
}
if (failed) {
cc.eventManager.removeListener(this._updateListener);
// cc.director.loadScene("Login");
}
if (needRestart) { //重新启动游戏
cc.eventManager.removeListener(this._updateListener);
// Prepend the manifest's search path
var searchPaths = jsb.fileUtils.getSearchPaths();
var newPaths = this._am.getLocalManifest().getSearchPaths();
Array.prototype.unshift(searchPaths, newPaths);
// This value will be retrieved and appended to the default search path during game startup,
// please refer to samples/js-tests/main.js for detailed usage.
// !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
console.log("测试===getPath",searchPaths);
jsb.fileUtils.setSearchPaths(searchPaths);
cc.game.restart();
}
},
hotUpdate: function () {
if (this._am && this._needUpdate) {
console.log("kaishi_______needupdate");
this._updateListener = new jsb.EventListenerAssetsManager(this._am, this.updateCb.bind(this));
cc.eventManager.addListener(this._updateListener, 1);
this._failCount = 0;
this._am.update();
}
},
// use this for initialization
onLoad: function () {
// Hot update is only available in Native build
if (!cc.sys.isNative) {
return;
}
console.log("热更新部分");
var storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'remote-asset');
cc.log('Storage path for remote asset : ' + storagePath);
cc.log('Local manifest URL : ' + this.manifestUrl);
console.log('Local manifest URL : ' + this.manifestUrl);
this._am = new jsb.AssetsManager(this.manifestUrl, storagePath);
var searchPaths = jsb.fileUtils.getSearchPaths();
cc.log("搜索路径",searchPaths);
4
this._am.retain();
this._needUpdate = false;
if (this._am.getLocalManifest().isLoaded())
{
this._checkListener = new jsb.EventListenerAssetsManager(this._am, this.checkCb.bind(this));
cc.eventManager.addListener(this._checkListener, 1);
this._am.checkUpdate();
}
},
onDestroy: function () {
this._am && this._am.release();
}
});
- 修改version到你要热更新的版本,高于线上才能更新,执行version_generator.js,生成manifest清单文件
打开cmd,切换到当前项目根目录下,执行下方命令:
//由于我们version_generator文件中,都配置好了参数
//因此可以简单调用以下命令即可
>node version_generator.js
- 生成两个配置文件project.manifest,version.manifest,在assets目录下
- 构建项目,在build目录下生成src,res,脚本和资源
- 搭建服务器,访问地址是http://xxxx:8080/hotupdate/,把上面生成的文件丢进去
- 测试一把,把version_generator.js中的version改低一点,执行node version_generator.js,构建项目,运行,成功!