Code Monkey home page Code Monkey logo

cocos-tutorial-hot-update's Introduction

资源热更新教程

前言

本篇文档基于 Cocos Creator v3.0.0 完成

之所以这篇文档的标题为教程,是因为目前 Cocos Creator 资源热更新的工作流还没有彻底集成到编辑器中,不过引擎本身对于热更新的支持是完备的,所以借助一些外围脚本和一些额外的工作就可以达成。

本篇文档的范例工程可以从 Github 仓库获取。

使用场景和设计思路

资源热更新的使用场景相信游戏开发者都非常熟悉,对于已发布的游戏,在游戏内通过从服务器动态下载新的游戏内容,来时刻保持玩家对游戏的新鲜感,是保持一款游戏长盛不衰非常重要的手段。当然热更新还有一些其他的用途,不过在此不再深入讨论,我们下面将主要讨论 Cocos Creator 对热更新支持的原理和手段。

Cocos Creator 中的热更新主要源于 Cocos 引擎中的 AssetsManager 模块对热更新的支持。它有个非常重要的特点:

服务端和本地均保存完整版本的游戏资源,热更新过程中通过比较服务端和本地版本的差异来决定更新哪些内容。这样即可天然支持跨版本更新,比如本地版本为 A,远程版本是 C,则直接更新 A 和 C 之间的差异,并不需要生成 A 到 B 和 B 到 C 的更新包,依次更新。所以,在这种设计思路下,新版本的文件以离散的方式保存在服务端,更新时以文件为单位下载。

除此之外,由于 WEB 版本可以通过服务器直接进行版本更新,所以资源热更新只适用于原生发布版本。AssetsManager 类也只在 jsb 命名空间下,在使用的时候需要注意判断运行环境。

Manifest 文件

对于不同版本的文件级差异,AssetsManager 中使用 Manifest 文件来进行版本比对。本地和远端的 Manifest 文件分别标示了本地和远端的当前版本包含的文件列表和文件版本,这样就可以通过比对每个文件的版本来确定需要更新的文件列表。

Manifest 文件中包含以下几个重要信息:

  1. 远程资源包的根路径
  2. 远程 Manifest 文件地址
  3. 远程 Version 文件地址(非必需)
  4. 主版本号
  5. 文件列表:以文件路径来索引,包含文件版本信息,一般推荐用文件的 md5 校验码来作为版本号
  6. 搜索路径列表

其中 Version 文件内容是 Manifest 文件内容的一部分,不包含文件列表。由于 Manifest 文件可能比较大,每次检查更新的时候都完整下载的话可能影响体验,所以开发者可以额外提供一个非常小的 Version 文件。AssetsManager 会首先检查 Version 文件提供的主版本号来判断是否需要继续下载 Manifest 文件并更新。

在 Cocos Creator 项目中支持热更新

在这篇教程中,将提出一种针对 Cocos Creator 项目可行的热更新方案,不过我们将在 Cocos2d-x 的未来版本中开放 Downloader 的 JavaScript 接口,届时用户可以自由开发自己的热更新方案。对于 Cocos Creator 来说,所有 JS 脚本将会打包到 src 目录中,其他 Assets 资源将会被导出到 assets 目录。

基于这样的项目结构,本篇教程中的热更新思路很简单:

  1. 基于原生打包目录中的 assets 和 src 目录生成本地 Manifest 文件。
  2. 创建一个热更新组件来负责热更新逻辑。
  3. 游戏发布后,若需要更新版本,则生成一套远程版本资源,包含 assets 目录、src 目录和 Manifest 文件,将远程版本部署到服务端。
  4. 当热更新组件检测到服务端 Manifest 版本不一致时,就会开始热更新

使用 Version Generator 来生成 Manifest 文件

在范例工程中,我们提供了一个 version_generator.js 文件,这是一个用于生成 Manfiest 文件的 NodeJS 脚本。使用方式如下:

> node version_generator.js -v 1.0.0 -u http://your-server-address/tutorial-hot-update/remote-assets/ -s native/package/ -d assets/

下面是参数说明:

  • -v 指定 Manifest 文件的主版本号。
  • -u 指定服务器远程包的地址,这个地址需要和最初发布版本中 Manifest 文件的远程包地址一致,否则无法检测到更新。
  • -s 本地原生打包版本的目录相对路径。
  • -d 保存 Manifest 文件的地址。

热更新组件

在范例工程中,热更新组件的实现位于 assets/hotupdate/HotUpdate.js 中,开发者可以参考这种实现,也可以自由得按自己的需求修改。

除此之外,范例工程中还搭配了一个 Canvas/update 节点用于提示更新和显示更新进度供参考。

部署远程服务器

为了让游戏可以检测到远程版本,可以在本机上模拟一个远程服务器,搭建服务器的方案多种多样(比如 Python SimpleHTTPServer),这里不做讨论,开发者可以使用自己习惯的方式。搭建成功后,访问远程包和 Manifest 文件的地址与范例工程中不同,所以需要修改以下几个地方来让游戏可以成功找到远程包:

  1. assets/project.manifest:游戏的本地 Manifest 文件中的 packageUrlremoteManifestUrlremoteVersionUrl
  2. remote-assets/project.manifest:远程包的 Manifest 文件中的 packageUrlremoteManifestUrlremoteVersionUrl
  3. remote-assets/version.manifest:远程包的 Version 文件中的 packageUrlremoteManifestUrlremoteVersionUrl

打包原生版本

下载完成范例工程后,可以用 Cocos Creator 直接打开这个工程。打开构建发布面板,构建原生版本,建议使用 Windows / Mac 来测试。 注意

  • 构建时请不要勾选 MD5 Cache,否则会导致热更新无效。
  • 并且应该确保在工程目录的 packages 文件夹里导入 hot-update 编辑器插件(范例工程里已经导入了该插件)

该编辑器插件会在每次构建结束后,自动给 main.js 附加上搜索路径设置的逻辑和更新中断修复代码:

// 在 main.js 的开头添加如下代码
(function () {
    if (typeof window.jsb === 'object') {
        var hotUpdateSearchPaths = localStorage.getItem('HotUpdateSearchPaths');
        if (hotUpdateSearchPaths) {
            var paths = JSON.parse(hotUpdateSearchPaths);
            jsb.fileUtils.setSearchPaths(paths);

            var fileList = [];
            var storagePath = paths[0] || '';
            var tempPath = storagePath + '_temp/';
            var baseOffset = tempPath.length;

            if (jsb.fileUtils.isDirectoryExist(tempPath) && !jsb.fileUtils.isFileExist(tempPath + 'project.manifest.temp')) {
                jsb.fileUtils.listFilesRecursively(tempPath, fileList);
                fileList.forEach(srcPath => {
                    var relativePath = srcPath.substr(baseOffset);
                    var dstPath = storagePath + relativePath;

                    if (srcPath[srcPath.length] == '/') {
                        jsb.fileUtils.createDirectory(dstPath)
                    }
                    else {
                        if (jsb.fileUtils.isFileExist(dstPath)) {
                            jsb.fileUtils.removeFile(dstPath)
                        }
                        jsb.fileUtils.renameFile(srcPath, dstPath);
                    }
                })
                jsb.fileUtils.removeDirectory(tempPath);
            }
        }
    }
})();

这一步是必须要做的原因是,热更新的本质是用远程下载的文件取代原始游戏包中的文件。Cocos2d-x 的搜索路径恰好满足这个需求,它可以用来指定远程包的下载地址作为默认的搜索路径,这样游戏运行过程中就会使用下载好的远程版本。另外,这里搜索路径是在上一次更新的过程中使用 localStorage(它符合 WEB 标准的 Local Storage API)固化保存在用户机器上,HotUpdateSearchPaths 这个键值是在 HotUpdate.js 中指定的,保存和读取过程使用的名字必须匹配。

此外,打开工程过程中如果遇到这个警告可以忽略:loader for [.manifest] not exists!

运行范例工程

如果一切正常,此时运行原生版本的范例工程,就会发现检测到新版本,提示更新,更新之后会自动重启游戏,此时可进入 table 场景。

结语

以上介绍的是目前一种可能的热更新方案,Cocos Creator 在未来版本中提供更成熟的热更新方案,直接集成到编辑器中。当然,也会提供底层 Downloader API 来允许用户自由实现自己的热更新方案,并通过插件机制在编辑器中搭建完整可视化的工作流。这篇教程和范例工程提供给大家参考,并不是官方方案,也鼓励开发者针对自己的工作流进行定制。如果有问题和交流也欢迎反馈到论坛中。

参考

资源管理器 Assets Manager 文档

cocos-tutorial-hot-update's People

Contributors

drelaptop avatar jareguo avatar knoxhuang avatar nantas avatar pandamicro avatar pppro avatar stormslowly avatar xianyinchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cocos-tutorial-hot-update's Issues

可以麻煩更新最新版本的資源熱更新教學嗎?

你好,

不好意思,我還是Cocos Creator的新手
我嘗試要測試 Asset Manager 的工具
但使用Build 打包 Windows 版本後
native/package/ 這個路徑還是沒有檔案
但看到Version Generator 來生成 Manifest 檔案的指令會用到這個路徑的檔案
node version_generator.js -v 1.0.0 -u http://your-server-address/tutorial-hot-update/remote-assets/ -s native/package/ -d assets/
不知道是不是有什麼操作我不懂所以漏掉了?

然後看到要寫到 main.js 附加上搜尋路徑設定的邏輯和更新中斷修復程式碼 也改到 hot-update 插件中了
不是很清楚要怎麼操作才能產生用來Patch 的 Asset 的檔案

希望有簡易的SOP操作順序能方便照著做
再麻煩有空能更新一下教學了
感謝~

热更下载文件报错

我用Nginx配置了一个文件下载服务器,manifest文件是可以下载下来的,但是下载热更资源的时候,就会报错,有的时候是 couldn't connect to server ,有的时候是,couldn't resolve host name,但是我manifest文件都下载下来了啊,都没有问题的,这个是为什么呢?

verstion_generator.js md5 计算和标准计算方法不一致。

const crypto = require('crypto')
const fs = require('fs')
const execSync = require('child_process').execSync

const filePath  = process.argv[2]
const md5ByBinary = crypto.createHash('md5').update(fs.readFileSync(filePath, 'binary'))
	.digest('hex');
const md5ByBuffer = crypto.createHash('md5').update(fs.readFileSync(filePath))
	.digest('hex');
const cliMd5 = process.platform==='darwin' ?'md5':'md5sum'

console.log({filePath,md5ByBinary, md5ByBuffer})
console.log('\ncli:')
console.log(execSync(`${cliMd5} ${filePath}`).toString())
// in macos
node md5veify.js HelloWorld.png
{ filePath: 'HelloWorld.png',
  md5ByBinary: 'a69a0b857f7462f4dd0d00bb5231a721',
  md5ByBuffer: '55ea4e952bf080f300379ec26723598b' }

cli:
MD5 (HelloWorld.png) = 55ea4e952bf080f300379ec26723598b

Mac环境导入creator V1.6.2版本 init报错

2017-10-27T09:22:29.555Z - normal: Initializing project /Users/XXXXX/creator/tutorial-hot-update
2017-10-27T09:22:29.559Z - normal: Loading packages
2017-10-27T09:22:29.574Z - normal: [Lua Support] version 1.1.6
2017-10-27T09:22:29.576Z - success: creator-lua-support loaded
2017-10-27T09:22:29.579Z - success: hot-update loaded
2017-10-27T09:22:29.579Z - normal: Watching packages
2017-10-27T09:22:29.628Z - normal: Run Application
2017-10-27T09:22:33.938Z - failed: [db-task][init] Failed to post import asset /Users/XXXXX/creator/tutorial-hot-update/assets/font/stake_number.fnt, message: TypeError: Cannot read property 'uuid' of undefined
at BitmapFontMeta.postImport (/Applications/CocosCreator.app/Contents/Resources/app.asar/editor/share/assets/meta/bitmap-font.js:1:1139)
at Async.series.e (/Applications/CocosCreator.app/Contents/Resources/app.asar/asset-db/lib/tasks.js:1:5804)
at /Applications/CocosCreator.app/Contents/Resources/app.asar/node_modules/async/lib/async.js:718:13
at iterate (/Applications/CocosCreator.app/Contents/Resources/app.asar/node_modules/async/lib/async.js:262:13)
at async.forEachOfSeries.async.eachOfSeries (/Applications/CocosCreator.app/Contents/Resources/app.asar/node_modules/async/lib/async.js:281:9)
at _parallel (/Applications/CocosCreator.app/Contents/Resources/app.asar/node_modules/async/lib/async.js:717:9)
at Object.async.series (/Applications/CocosCreator.app/Contents/Resources/app.asar/node_modules/async/lib/async.js:739:9)
at _postImportAsset (/Applications/CocosCreator.app/Contents/Resources/app.asar/asset-db/lib/tasks.js:1:5734)
at Async.eachLimit.Async.ensureAsync (/Applications/CocosCreator.app/Contents/Resources/app.asar/asset-db/lib/tasks.js:1:7544)
at /Applications/CocosCreator.app/Contents/Resources/app.asar/node_modules/async/lib/async.js:1213:16
2017-10-27T09:22:34.467Z - success: preview server running at http://localhost:7456
2017-10-27T09:22:39.903Z - normal: 1.6.2

ccc1.10.2遇到ERROR_DOWNLOAD_MANIFEST怎么办?

case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
this.panel.info.string = "Fail to download manifest file, hot update skipped.";
break;

请问上面的写法是正确的吗?
详细的报错请看这里:
http://www.cocoachina.com/bbs/read.php?tid=1793137&page=1&toread=1#tpc
麻烦帮忙看一下,谢谢。

因为下载错误,我现在已经用downFile2Local的形式,已经能下载到文件了,但是我不知道怎么把缓存文件夹里面的文件覆盖到程序的文件夹啊。(我是在电脑上自带模拟器测试的,缓存地址是模拟器主程序目录下面的一个_temp文件夹,但是明显跟项目的路径差很远的,我不知道手机上会是是什么样子)

安卓更新完毕重启,检查更新发现还是有更新。

更新完成重新启动,点击检查更新按钮,发现还是可以找到更新版本。
再三确认提示更新完成,而不是更新失败。

查看设备内数据,发现storagePath目录下面没有任何东西。
var storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'blackjack-remote-asset');
console.log('Storage path for remote asset : ' + storagePath);
但是在storagePath_temp目录下面有一个version文件。

logcat日志
http://url.cn/45RIvYP

creator版本1.4
开发环境windows
安卓机型 小米

hot update load script but error 5000 (cocos creator 1.9.1)

here file main.js

`(function () {

function boot () {

    var settings = window._CCSettings;
    window._CCSettings = undefined;

    if ( !settings.debug ) {
        var uuids = settings.uuids;

        var rawAssets = settings.rawAssets;
        var assetTypes = settings.assetTypes;
        var realRawAssets = settings.rawAssets = {};
        for (var mount in rawAssets) {
            var entries = rawAssets[mount];
            var realEntries = realRawAssets[mount] = {};
            for (var id in entries) {
                var entry = entries[id];
                var type = entry[1];
                // retrieve minified raw asset
                if (typeof type === 'number') {
                    entry[1] = assetTypes[type];
                }
                // retrieve uuid
                realEntries[uuids[id] || id] = entry;
            }
        }

        var scenes = settings.scenes;
        for (var i = 0; i < scenes.length; ++i) {
            var scene = scenes[i];
            console.log('scene.url',scene.url)
            if (typeof scene.uuid === 'number') {
                scene.uuid = uuids[scene.uuid];
            }
        }

        var packedAssets = settings.packedAssets;
        for (var packId in packedAssets) {
            var packedIds = packedAssets[packId];
            for (var j = 0; j < packedIds.length; ++j) {
                if (typeof packedIds[j] === 'number') {
                    packedIds[j] = uuids[packedIds[j]];
                }
            }
        }
    }

    // init engine
    var canvas;

    if (cc.sys.isBrowser) {
        canvas = document.getElementById('GameCanvas');
    }

    if (false) {
        var ORIENTATIONS = {
            'portrait': 1,
            'landscape left': 2,
            'landscape right': 3
        };
        BK.Director.screenMode = ORIENTATIONS[settings.orientation];
        initAdapter();
    }

    function setLoadingDisplay () {
        // Loading splash scene
        var splash = document.getElementById('splash');
        var progressBar = splash.querySelector('.progress-bar span');
        cc.loader.onProgress = function (completedCount, totalCount, item) {
            var percent = 100 * completedCount / totalCount;
            if (progressBar) {
                progressBar.style.width = percent.toFixed(2) + '%';
            }
        };
        splash.style.display = 'block';
        progressBar.style.width = '0%';

        cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function () {
            splash.style.display = 'none';
        });
    }

    var onStart = function () {
        cc.view.resizeWithBrowserSize(true);

        if (!false && !false) {
            // UC browser on many android devices have performance issue with retina display
            if (cc.sys.os !== cc.sys.OS_ANDROID || cc.sys.browserType !== cc.sys.BROWSER_TYPE_UC) {
                cc.view.enableRetina(true);
            }
            if (cc.sys.isBrowser) {
                setLoadingDisplay();
            }

            if (cc.sys.isMobile) {
                if (settings.orientation === 'landscape') {
                    cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
                }
                else if (settings.orientation === 'portrait') {
                    cc.view.setOrientation(cc.macro.ORIENTATION_PORTRAIT);
                }
                cc.view.enableAutoFullScreen([
                    cc.sys.BROWSER_TYPE_BAIDU,
                    cc.sys.BROWSER_TYPE_WECHAT,
                    cc.sys.BROWSER_TYPE_MOBILE_QQ,
                    cc.sys.BROWSER_TYPE_MIUI,
                ].indexOf(cc.sys.browserType) < 0);
            }

            // Limit downloading max concurrent task to 2,
            // more tasks simultaneously may cause performance draw back on some android system / brwosers.
            // You can adjust the number based on your own test result, you have to set it before any loading process to take effect.
            if (cc.sys.isBrowser && cc.sys.os === cc.sys.OS_ANDROID) {
                cc.macro.DOWNLOAD_MAX_CONCURRENT = 2;
            }
        }

        // init assets
        cc.AssetLibrary.init({
            libraryPath: 'res/import',
            rawAssetsBase: 'res/raw-',
            rawAssets: settings.rawAssets,
            packedAssets: settings.packedAssets,
            md5AssetsMap: settings.md5AssetsMap
        });

        if (false) {
            cc.Pipeline.Downloader.PackDownloader._doPreload("WECHAT_SUBDOMAIN", settings.WECHAT_SUBDOMAIN_DATA);
        }

        var launchScene = settings.launchScene;

        // load scene
        cc.director.loadScene(launchScene, null,
            function () {
                if (cc.sys.isBrowser) {
                    // show canvas
                    canvas.style.visibility = '';
                    var div = document.getElementById('GameDiv');
                    if (div) {
                        div.style.backgroundImage = '';
                    }
                }
                cc.loader.onProgress = null;
                console.log('Success to load scene: ' + launchScene);
            }
        );
    };

    // jsList
    var jsList = settings.jsList;

    if (false) {
        BK.Script.loadlib();
    }
    else
    {
        var bundledScript = settings.debug ? 'src/project.dev.js' : 'src/project.js';
        if (jsList) {
            jsList = jsList.map(function (x) {
                return 'src/' + x;
            });
            jsList.push(bundledScript);
        }
        else {
            jsList = [bundledScript];
        }
    }

    // anysdk scripts
    if (cc.sys.isNative && cc.sys.isMobile) {

// jsList = jsList.concat(['src/anysdk/jsb_anysdk.js', 'src/anysdk/jsb_anysdk_constants.js']);
}

    var option = {
        //width: width,
        //height: height,
        id: 'GameCanvas',
        scenes: settings.scenes,
        debugMode: settings.debug ? cc.DebugMode.INFO : cc.DebugMode.ERROR,
        showFPS: (!false && !false) && settings.debug,
        frameRate: 60,
        jsList: jsList,
        groupList: settings.groupList,
        collisionMatrix: settings.collisionMatrix,
        renderMode: 0
    }

    cc.game.run(option, onStart);
}

if (false) {
    BK.Script.loadlib('GameRes://libs/qqplay-adapter.js');
    BK.Script.loadlib('GameRes://src/settings.js');
    BK.Script.loadlib();
    BK.Script.loadlib('GameRes://libs/qqplay-downloader.js');
    qqPlayDownloader.REMOTE_SERVER_ROOT = "";
    var prevPipe = cc.loader.md5Pipe || cc.loader.assetLoader;
    cc.loader.insertPipeAfter(prevPipe, qqPlayDownloader);
    // <plugin script code>
    boot();
    return;
}

if (false) {
    require(window._CCSettings.debug ? 'cocos2d-js.js' : 'cocos2d-js-min.js');
    var prevPipe = cc.loader.md5Pipe || cc.loader.assetLoader;
    cc.loader.insertPipeAfter(prevPipe, wxDownloader);
    boot();
    return;
}
 if (window.cc && cc.sys.isNative) { 
    var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths'); 
    console.log('hotUpdateSearchPaths',hotUpdateSearchPaths)
    if (hotUpdateSearchPaths) { 
        jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths)); 
    }
}

if (window.jsb) {
    require('src/settings.js');
    require('src/jsb_polyfill.js');
    boot();
    return;
}


if (window.document) {
    var splash = document.getElementById('splash');
    splash.style.display = 'block';

    var cocos2d = document.createElement('script');
    cocos2d.async = true;
    cocos2d.src = window._CCSettings.debug ? 'cocos2d-js.js' : 'cocos2d-js-min.js';

    var engineLoaded = function () {
        document.body.removeChild(cocos2d);
        cocos2d.removeEventListener('load', engineLoaded, false);
        window.eruda && eruda.init() && eruda.get('console').config.set('displayUnenumerable', false);
        boot();
    };
    cocos2d.addEventListener('load', engineLoaded, false);
    document.body.appendChild(cocos2d);
}

})();
`

STACK:
[0]_onPreDestroy@src/jsb_polyfill.js:14188
[1]_onPreDestroy@src/jsb_polyfill.js:1751
[2]98.u._destroyImmediate@src/jsb_polyfill.js:11995
[3]_onPreDestroy@src/jsb_polyfill.js:14186
[4]_onPreDestroy@src/jsb_polyfill.js:1751
[5]98.u._destroyImmediate@src/jsb_polyfill.js:11995
[6]_onPreDestroy@src/jsb_polyfill.js:14186
[7]_onPreDestroy@src/jsb_polyfill.js:1751
[8]98.u._destroyImmediate@src/jsb_polyfill.js:11995
[9]_onPreDestroy@src/jsb_polyfill.js:14186
[10]_onPreDestroy@src/jsb_polyfill.js:1751
[11]98.u._destroyImmediate@src/jsb_polyfill.js:11995
[12]_onPreDestroy@src/jsb_polyfill.js:14186
[13]_onPreDestroy@src/jsb_polyfill.js:1751
[14]98.u._destroyImmediate@src/jsb_polyfill.js:11995
[15]s@src/jsb_polyfill.js:11892
[16]callback@src/jsb_polyfill.js:18235
E/jswrapper (519): [ERROR] (..\jswrapper\v8\Object.cpp, 519): Invoking function (09829418) failed!
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
D/jswrapper (125): JS: [ERROR]: Error 5000, please go to https://github.com/cocos-creator/engine/blob/master/EngineErrorMap.md#5000 to see details.
E/jswrapper (267): ERROR: Uncaught TypeError: Cannot read property '_destroyImmediate' of null, location: src/jsb_polyfill.js:0:0

this.manifestUrl.nativeUrl值为空

我的引擎版本是2.1.1,但是在真机上一直显示this.manifestUrl.nativeUrl(在HotUpdate.js中)为undifined,请问这个值我该如何配置比较好,谢谢~

creator 2.1.2构建window无法运行

creator 2.1.2构建window项目,编译后运行界面黑的,并且 有错误提示
ERROR: Uncaught TypeError: Cannot read property 'length' of null, location: src/cocos2d-jsb.js:0:0
[ERROR] (d:\cocoscreator_2.1.2\resources\cocos2d-x\cocos\scripting\js-bindings\jswrapper\v8\object.cpp, 534): Invoking function (0D8D0740) failed!

大版本更新问题

如果遇到大版本更新,比如apk重新更新,如何重置缓存更新目录? 可以用 cc.sys.osVersion 和 cc.sys.osMainVersion 来控制吧?那是不是必须得在main.js里面添加控制逻辑

cc.eventManager问题

版本1.8,1.9去除了cc.eventManager,请问check和update发出的事件名称是什么?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.