creator js热更新

creator   热更新方法:

大致原理:

creator 打包出来的工程目录和vs项目的目录基本相同,在客户端实际执行的文件其实就是build目录下的src和res文件,游戏中只要动态的改变src res 内容即可达到热更新的目的。

实际上资源包里的文件不可能修改,但是可以在游戏运行开始时设置搜索路径,将需要更新的资源的路径放在搜索路径的最前面即可在加载游戏时优先加载需要热更新的文件,间接达到热更新的目的。

过程:

1、在服务器端放置一个记录版本号的文件 project.manifest文件(此文件用md5值记录当前版本)

2、在服务器端放置 需要热更新的src   res 文件(在creator中点击构建项目 生成的build 目录下的src res 文件)

3、客户端本地也存放有一个记录版本号的文件 project.manifest (此文件用md5值记录当前版本)

4、在游戏启动后先加载服务器中的project.manifest文件 然后与本地的project.manifest文件对比 得出哪些文件需要加载(对比部分有引擎内部调用,用户程序中不用管)

5、下载服务器中的需要更新的src res文件    并保存到客户端的可写路径中 (可以将这个可写路径保存在userdefault中 在后面游戏启动时设置搜索路径)

6、重启游戏

7、在游戏启动时(main.js)中设置上一步的可写路径为搜索路径并前置(保证游戏加载的是最新的版本)

操作

1、生成project.manifest版本文件

在插件商店中下载 安装

生成manifest文件

creator中 点击 扩展---》热更新工具

版本号:                            要求服务器中的版本号要高于本地的版本号(程序中利用对比版本号决定是否下载新版本   版本对比方法可以自己设置也可以用默认方法  )

资源服务器跟目录:            就是服务器中 src  和res 的上层目录

build项目资源文件目录:   用creator构建出的项目的build/jsb-default目录

manifest存储目录:

生成的manifest文件目录(这里直接放置assets目录下了  ,有人说需要生成在别的地方,然后在copy到工程项目中

不然会出问题,但是经测试这么做没有问题。。。。。)

点击生成    会在manifest存储目录中生成两个manifest文件(project.manifest 和version.manifest)

这里需要注意的是:

1.每次在生成manifest文件前都需要重新构建项目(保证manifest文件标识的是最新的文件) 只需要构建 不用编译

2.version.manifest里的内容实际上只是project.manifest文件的一部分,version文件只标识:远程包的 Manifest 文件中的packageUrl、remoteManifestUrl和remoteVersionUrl,

project文件还包含了每个src 和res

文件的md5值,当工程非常大是此文件可能比较大,添加一个version 文件的目的就是方便每次判断版本时先下载一个尽量小的version文件

先判断版本号是否一致 再决定是否需要下载更新project文件(优化    此部分用户也不需要管 ,引擎内部已封装)

2、部署服务器,

再web服务器中放置 由creator生成的 src ,res,versin.manifest,    project.manifest文件 (也可以搭建本地服务器测试  具体搭建过程自行百度 。。。。。)

项目热更新代码:

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

},

checkCb: function (event) {

cc.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);

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);

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);

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);

break;

default:

break;

}

this.hotUpdate();

},

updateCb: function (event) {

var needRestart = false;

var failed = false;

switch (event.getEventCode())

{

case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:

cc.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();

if (msg) {

cc.log(msg);

}

this.progress.getComponent(cc.Label).string = "文件进度:" + percent.toFixed(2) * 100 + "%"

cc.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.');

this.tip.getComponent(cc.Label).string = "已经是最新版本";

failed = true;

break;

case jsb.EventAssetsManager.UPDATE_FINISHED:

cc.log('Update finished. ' + event.getMessage());

this.tip.getComponent(cc.Label).string = "更新完成:正在重启游戏";

needRestart = true;

break;

case jsb.EventAssetsManager.UPDATE_FAILED:

cc.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());

break;

case jsb.EventAssetsManager.ERROR_DECOMPRESS:

cc.log(event.getMessage());

break;

default:

break;

}

if (failed) {

cc.eventManager.removeListener(this._updateListener);

}

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) {

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);

this._am = new jsb.AssetsManager(this.manifestUrl, storagePath);

var searchPaths = jsb.fileUtils.getSearchPaths();

cc.log("搜索路径",searchPaths);

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();

}

});

3、将 src  res   version.manifest   project.manifest 文件放置到服务器中(与manifest文件中远程服务器目录一致)

4、随便修改项目(与服务器中项目作区别)

5、构建项目 ----》重新生成manifest文件(按照上面的步骤  版本号要低于服务器上的版本号)

这里注意:

服务器上的版本和本地版本 需要都是release版本,或者都是debug版本 否则会出现jsc文件的优先级高于js文件导致更新成功但热更新资源不生效的问题

6、编译打包 测试

这是就会看到更新到了服务器的最新版本

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • Correctness AdapterViewChildren Summary: AdapterViews can...
    MarcusMa阅读 8,849评论 0 6
  • 1.除了方法, 其他东西都要扔到properties里面了, 并且要给出属性的默认值或者属性的存取的方法 1) 首...
    视掘阅读 1,322评论 0 0
  • 人们总说, 相爱的两个人总有一些相似的地方, 他们可能喜欢一样的风景, 可能喜欢吃一样的菜, 我们都在同一个校园里...
    李大木阅读 131评论 0 0
  • 人类一直以来都反对寻找外星人,无外乎害怕外星人入侵,然而,这无非是人类自身的本体思维在作怪而已。大家回想一下在人类...
    奶酪会变质阅读 333评论 0 2