HotUpdate.js 12 KB
// var md5 = require("md5")
let  EventCenter = require("EventCenter")
var g_check = false;
cc.Class({
    extends: cc.Component,

    properties: {
        _searchPath: "",//搜索路径
        manifestUrl: {
            type: cc.Asset,     // use 'type:' to declare an object reference
            default: null,      // object's default value is null
        },

        _checkUpdate: false,
        _checkUpdateNum: 5,//检查更新次数
        _updating: false,//正在检查更新或者更新中
        _isForceUpdate: false,

        _loadFiles: "yybs-remote-asset",

        byteProgress: cc.ProgressBar,//字节进度
        fileProgress: cc.ProgressBar,//文件进度
        info: cc.Label,//信息显示
        fileLabel: cc.Label,//文件个数
        byteLabel: cc.Label,//字节个数

        // retryBtn: cc.Button,//重置按钮
        // checkBtn: cc.Button,//检查更新按钮 目前是自动得
        // updateBtn: cc.Button,//更新按钮  目前是自动的

        forceUpdate: cc.Layout,//强更界面
        ensureBut: cc.Button,//确定按钮
        _forceHotUpdate: "",
    },
    start() {
        // if (CC_DEBUG) {//发布debug模式apk跳过热更

        //     this.startGame();//隐藏当前ui//多场景时 这直接加载下一个场景
        // }
        if (!cc.sys.isNative)//web//跳过热更 
        {
            this.startGame();//隐藏当前ui//多场景时 这直接加载下一个场景
        }
        else {
            this.hotUpdateInit();
            this.hotUpdateLogic();//热更逻辑
            var delay = cc.delayTime(10);
            var finishedAll = cc.callFunc(this.overTimeStartGame, this);
            this.node.runAction(cc.sequence(delay, finishedAll));
        }
    },

    checkCb: function (event) {
        this._checkUpdate = false;//检测更新完毕
        this._updating = false;//更新中
        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                this.showUpDateInfo('检查更新失败');
                g_check = true;
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                this.showUpDateInfo('检查更新失败');
                g_check = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                this.showUpDateInfo('已是最新版本');
                if (this._isForceUpdate == false) {
                    this.startGame();
                    return;
                }
                break;
            case jsb.EventAssetsManager.NEW_VERSION_FOUND:
                this.showUpDateInfo('发现新版本,正在更新...');
                g_check = false;
                break;
            default:
                return;
        }
        if (g_check == true) {
            this.checkUpdate();
        }
        else {
            this.hotUpdate();
        }

    },

    overTimeStartGame: function () {
        if (this.node.active == true && this._checkUpdate == true) {
            this.startGame();
        }
    },
    startGame: function ()//开始游戏
    {
        this.node.active = false;
        cc.log("开始游戏");
        EventCenter.EventCenter.GameStart.emit();
    },
    hotUpdateInit: function () {

        var self = this;
        this.ensureBut.node.on('click', function (event) {
            self.ensureButCallBack();
        }, this);
    },
    ensureButCallBack: function ()//确定按钮回掉
    {
        // cc.sys.openURL('http://formal.share.idj66nm.com/down/link?gameId=200001&gameState=1');//强更下载地址
        cc.director.end();
    },
    hotUpdateLogic: function ()//热更逻辑
    {
        this.initAssetsManager();
        this.checkUpdate();
    },
    forceUpdateLogic: function ()//强更逻辑
    {
        this._isForceUpdate = true;
        this.forceUpdate.node.active = true;
    },
    initAssetsManager: function ()//初始化
    {
        this._searchPath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + this._loadFiles);//获取热更时得搜索路径
        cc.log('hotUpdate searchPath =' + this._searchPath);
        var self = this;
        var versionCompareHandle = function (versionA, versionB) //版本对比函数(检查本地mainfest和远端mainfes时,如果返回值大于0 会自动更新)
        {
            cc.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
            var vA = versionA.split('.');
            var vB = versionB.split('.');
            if (vA.length != vB.length || vA.length < 3)
                return 0;
            if ((parseInt(vA[0]) != parseInt(vB[0])))//前两位控制大版本更新
            {
                //强制更新
                self.forceUpdateLogic();
                return 0;
            }
            self._forceHotUpdate = vA[0] + "" + vA[1];
            var forceUpdate = cc.sys.localStorage.getItem('forceupdateyybs');
            cc.log("initAssetsManager forceupdate " + forceUpdate);
            self._forceHotUpdate = vB[0] + "" + vB[1];
            for (var i = 0; i < vA.length; ++i) {
                var a = parseInt(vA[i]);
                var b = parseInt(vB[i] || 0);
                if (a === b) {
                    continue;
                }
                return -1;
            }
            if (vB.length > vA.length) {
                return -1;
            }
            cc.sys.localStorage.setItem('forceupdateyybs', self._forceHotUpdate);
            return 0;
        };
        this._am = new jsb.AssetsManager(this.manifestUrl, this._searchPath, versionCompareHandle);//初始化 创建 AssetsManager
        // if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS)
        // {
        //     this._am.retain();
        // }
        //用户文件校验接口 由于下载过程中仍然有小概率可能由于网络原因或其他网络库的问题导致下载的文件内容有问题,
        //在文件下载完成后热更新管理器会调用这个接口,如果返回 true 表示文件正常,返回 false 表示文件有问题
        this._am.setVerifyCallback(function (path, asset) {
            var compressed = asset.compressed;// 是压缩文件 不需要检查它的md5
            var expectedMD5 = asset.md5;//检索md5值。
            var relativePath = asset.path;// asset.path 是相对路径 path 绝对路径.
            var size = asset.size;//文件的大小,但是这个值可能不存在
            if (compressed) {
                return true;
            }
            else {
                return true;
                // //使用绝对路径来加载文件,之后计算md5值
                // var data = jsb.fileUtils.getDataFromFile(path);
                // var curMD5 = md5(data);
                // if (curMD5 == asset.md5) {
                //     //md5检验通过
                //     return true;
                // } else {
                //     //md5检验失败
                //     //this.info.string = relativePath + "文件MD5校验失败";
                //     cc.log("md5检验失败");
                //     return false;
                // }
            }
        });
        if (cc.sys.os === cc.sys.OS_ANDROID) {//控制下载并发数量的 API 有些Android设备可能会在并发任务太多时减慢下载速度。设置适合游戏的值。
            this._am.setMaxConcurrentTask(2);
        }
    },



    checkUpdate: function ()//检查更新
    {
        this._checkUpdateNum = this._checkUpdateNum - 1;
        if (this._checkUpdateNum <= 0) {
            //直接登陆
            this.startGame();
            return;
        }
        if (this._updating) {
            this.showUpDateInfo('正在检测或者更新中,请耐心等待...');
            return;
        }
        this._am.setEventCallback(this.checkCb.bind(this));

        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            var url = this.manifestUrl.nativeUrl;
            if (cc.loader.md5Pipe) {
                url = cc.loader.md5Pipe.transformURL(url);
            }
            cc.log('加载本地Manifest', url);
            this._am.loadLocalManifest(url);
        }
        this._am.checkUpdate();
        this._checkUpdate = true;//正在检测更新
        this.showUpDateInfo('正在检测更新,请耐心等待...');
    },


    hotUpdate: function () {
        if (this._am == null) {
            return;
        }

        this._am.setEventCallback(this.updateCb.bind(this));

        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            this._am.loadLocalManifest(this.manifestUrl);
        }
        this._am.update();
        this._updating = true;
    },
    updateCb: function (event) {
        var needRestart = false;
        var failed = false;
        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                cc.log('错误:没找到本地manifest文件');
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_PROGRESSION://更新进度
                this.byteProgress.progress = event.getPercent();
                this.fileProgress.progress = event.getPercentByFile();
                this.fileLabel.node.active = true;
                this.fileLabel.string = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
                this.byteLabel.string = event.getDownloadedBytes() / 1024 + ' / ' + event.getTotalBytes() / 1024;
                var msg = event.getMessage();
                if (msg) {
                    // cc.log(event.getPercent()/100 + '% : ' + msg);
                }
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                cc.log('错误:下载或解析MANIFEST文件失败');
                failed = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                this.showUpDateInfo('与服务器版本一致');
                if (this._isForceUpdate == false)
                    this.startGame();
                break;
            case jsb.EventAssetsManager.UPDATE_FINISHED:
                this.showUpDateInfo('更新完成');
                this._updating = false;
                needRestart = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FAILED://更新失败
                this._updating = false;
                failed = true;
                break;
            case jsb.EventAssetsManager.ERROR_UPDATING:
                if (event.getMessage()) {
                    this.info.string = '更新' + event.getAssetId() + '时发生错误.' + event.getMessage();
                } else {
                    this.info.string = '更新' + event.getAssetId() + '时发生错误';
                }
                needRestart = true;
                break;
            case jsb.EventAssetsManager.ERROR_DECOMPRESS:
                this.showUpDateInfo('解压发生错误.' + event.getMessage());
                break;
            default:
                break;
        }
        if (needRestart) {
            this.restartGame();
            return;
        }
        if (failed) {

            this._updating = false;
            this.checkUpdate();
        }
    },
    onDestroy: function () {
        if (this._am)
            this._am.setEventCallback(null);
    },
    restartGame: function ()//重启游戏
    {

        this.fileProgress.progress = 1;
        this.byteProgress.progress = 1
        var searchPaths = jsb.fileUtils.getSearchPaths();
        var newPaths = this._am.getLocalManifest().getSearchPaths();
        Array.prototype.unshift(searchPaths, newPaths);
        cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
        cc.sys.localStorage.setItem('forceupdateyybs', this._forceHotUpdate);
        jsb.fileUtils.setSearchPaths(searchPaths);
        cc.audioEngine.stopAll();
        cc.game.restart();
    },
    //显示更新信息
    showUpDateInfo: function (strInfo) {
        this.info.string = strInfo;
    }
});