cocos creator 热更新

1、下载version_generator.js 文件
,放入下面目录中

version_generator目录

或者直接贴代码

/**
 * 此模块用于热更新工程清单文件的生成
 */

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,构建项目,运行,成功!

你可能感兴趣的:(cocos creator 热更新)