热更新的坑,这种情况下热更新后的脚本不能执行

热更新文件脚本只能有一个project.dev.js,运行项目时只能识别初始化的project.dev.js文件。
比如项目热更新文件:
场景scene1热更新文件:
GameAssets/src、GameAssets/res、GameAssets/project.manifest,GameAssets/version.manifest
场景scene2热更新文件:
GameAssets/Game1/src,GameAssets/Game1/res、GameAssets/Game1/project.manifest,GameAssets/Game1/version.manifest

运行项目-热更新load后进入场景scene1,脚本和资源都为更新后的
在场景scene1中选择热更新Game1,热更load后进入场景scene2,发现资源已更新为GameAssets/res里的资源,脚本还是执行GameAssets/src/project.dev.js中的脚本,没有执行GameAssets/Game1/src/project.dev.js中的脚本

测试了好几次都是这样的,热更新正常,路径也正常,无论是构建scene1还是scene2生成manifest文件,都是一样的没执行到GameAssets/Game1/src/project.dev.js中的脚本。

是不是平台多游戏的项目,所有的脚本只能在平台的project.dev.js文件中一次性构建,不能分别为各个游戏建构
Games-assets.rar (444.1 KB)

最近问热更新的问题的人好多…

应该还是没有重启的原因,

此时应该已经加载了原始包内的 Game1/src/project.dev.js

这里应该是直接 load scene2,没错,Game1 的资源的确已经热更新下来了,但是并无法生效,因为不会重新 require Game1 的 project.dev.js,因为前面已经 require 过了。即便你强制手动 require 也不会成功,因为 ScriptingCore 中已经有了脚本缓存。即便你手动删除脚本缓存,增加搜索路径,重新 require 一次,也可能不会成功,因为此时旧的 project.dev.js 已经在内存中了,重新 require 会覆盖脚本内声明的类型,但是如果你执行过旧的脚本生成过任何对象,它们都是旧版本的对象,说不好会不会和新版本冲突。

以上就是为什么我们强调要在热更新后重启,才能够有效得让更新过的脚本生效。

热更完成后都做了重启操作调用cc.director.restart(),这对scene1第一次热更有效果。之后进入scene1都没什么问题,关键是由scene1进入scene2场景时,因为scene1的project.dev.js已在内存中了,所以无法再调用到热更后Game1/src/project.dev.js脚本。如果此时进行重启也只会对scene1的重启,又进入了scene1场景。并不会重启scene2场景

重启之后的逻辑是由你控制的,比如说你可以在重启前记录一下需要进入的场景,然后重启后,直接 load 那个场景。main.js 中的代码是用户控制的代码,所以不必完全按照引擎默认的来做。

在scene1下选择要进入的子游戏场景操作时记录scene2场景操作如下:
cc.Info = info;
cc.sys.localStorage.setItem(“cc.Info”,JSON.stringify(cc.Info));
** jsb.fileUtils.setSearchPaths([]);**
cc.director.restart();

重启后进入scene1的热更,在scene1热更之前进行判断,如有记录则直接进入子游戏的热更:
if( cc.sys.localStorage.getItem(“cc.Info”))
{
cc.Info = JSON.parse(cc.sys.localStorage.getItem(“cc.Info”));
cc.sys.localStorage.setItem(“cc.Info”,null);
cc.director.loadScene(“subLoading”);
return;
}

子游戏热更完成后进入所记录的场景
cc.director.loadScene(cc.Info.fire);

可是重启后还是执行scene1场景的project.dev.js,Game1/src/project.dev.js脚本并没有调用到,是不是我以上的方法不对呢

子游戏热更新完成后也一定要重启

子游戏热更完成后有重启的啊,就是没有调用到Game1/src/project.dev.js脚本
case jsb.EventAssetsManager.UPDATE_FINISHED:
needRestart = true;
break;

if (needRestart) {
cc.eventManager.removeListener(this._updateListener);
this._updateListener = null;
jsb.fileUtils.setSearchPaths([]);
cc.sys.localStorage.setItem(“cc.Info”,JSON.stringify(cc.Info));
cc.game.restart();
}

热更scene1场景和scene2场景,热更完成后都有更新的

子游戏更新完以后为什么把 searchPaths 设置为空? restart 的时候有没有预设进去子游戏的 searchPaths 呢?

没有预设,因为在new jsb.AssetsManager(this.manifestUrl,storagePath);会把storagePath路径设置到searchPaths里,在热更后进行scene2场景前,log所有的storagePath,
var paths = jsb.fileUtils.getSearchPaths();
for(var i in paths)
{
cc.log(“path:::”,i,paths[i]);
}
cc.director.loadScene(cc.Info.fire);

log如下:
path::: 0 C:/Users/Administrator/AppData/Local/Games/Games-assets/Game1/
path::: 1 C:/Users/Administrator/AppData/Local/Games/Games-assets/
path::: 2 F:/cocosCreator/project/GameFile/Games/build/jsb-link/frameworks/runtime-src/proj.win32/Debug.win32/res/raw-assets/
path::: 3 F:/cocosCreator/project/GameFile/Games/build/jsb-link/frameworks/runtime-src/proj.win32/Debug.win32/

是有scene2的缓存路径的:C:/Users/Administrator/AppData/Local/Games/Games-assets/Game1/

[quote=“panda, post:10, topic:44933, full:true”]
子游戏更新完以后为什么把 searchPaths 设置为空?
因为之前以为热更完成后重启时,之前的jsb.fileUtils缓存路径还存在,所以在重启之前加了设置为空。

看起来搜索路径没问题,那么可以在 ScriptingCore::compileScript 中下条件断点(路径等于你的 Game1 脚本相对路径时),然后跟踪一下看看 FileUtils 获取到的脚本完整路径是什么

我热更新这卡着了。求大神指点迷津;http://forum.cocos.com/t/topic/46583