解决Asset Bundle热更新之后脚本不生效的问题

一般bundle热更之后只能通过cc.game.restart重启游戏去刷新资源,并不能直接热加载脚本,那么问题就来了,本来bundle就是一个子游戏,为啥非要刷新整个游戏呢,这就有点蛋疼了,这次就是可以不用重启游戏的方法。

直接去找打包之后对应发布平台的的路径,在里面找到cocos2d-jsb.js这个文件
…/发布平台/src/cocos2d-jsb.js 发布平台 = jsb-link或者web-mobile或者web-desktop等等…






第一步


如图中所示,直接添加

js.delClassById = function(classId) {
    delete _idToClass[classId];
};
js.delClassByName = function(classname) {
    delete _nameToClass[classname];
};

第二步


在cc._RF的push函数当中添加一段代码

if(window.isLoadingBundle){
    cc.js.delClassById(uuid);
    cc.js.delClassByName(script);
}



此时就已经完成了,当热更完毕之后,重新加载bundle的时候先把 window.isLoadingBundle = true; 加载完之后再置为false。
window.isLoadingBundle = true;
cc.assetManager.loadBundle('TEST', (err, bundle) => {
    window.isLoadingBundle = false;
});



原理很简单,本质上就是当从加载bundle之后,会加载bundle里面的脚本,这个时候会走jsb-engine.js中的downloadScript这个函数。加载完之后会被require
image





此时require之后的js脚本有个立即执行函数,且恰巧cc.RF.push会传入我们需要的参数,这个问题就完美的解决了

6赞

给力,我帮你问问看引擎是否考虑也这样做。

1赞

我这边还有一个问题,本质上这套操作是为了清除在当前环境的缓存,让后续代码能够顺利执行setClassId和setClassName,但是源码当中提供了unregisterClass,我全局搜索了很多次,都没有看到有调用过。
image

图片

引擎大佬的回复,你的功能是否已经完成?

不用加其他的代码,原型链并没有替换,但是生成了一份新的脚本,等于是替换了,就是之前加载的脚本如何释放干净才是个问题

不建议这样做,最简单的方法就是先销毁然后再重新加载bundle即可


image

也是哦,这种方式也省心

不过我还是比较推荐引擎组这样系统性的试一下,我刚刚试了并没有内存泄漏。而且原型链也替换了,达到了热加载的功能了,脚本的打印也正确。

mark~~~~~~~

这个变数的缓存不清掉,脚本也不会重新加载

1赞

当前我的需求是主包与多个分包都有相同UUID的脚本,切换主包,分包的时候需要把该脚本切换为对应包的脚本。已经通过不修改引擎的方法实现了加载AB替换同UUID的脚本,但是同UUID脚本一个地址只能加载一次。这部分有什么线索呢?

脚本只能加载一次,我是通过打包时给AB包加上版本标识,加载AB包时注入版本解决的。至于类重新注册还是要改源码。

官方文档中加载AB包也是支持带版本的

我做的 2.4.x热更新大厅子游戏分包插件的商店链接

能实现不同AB包同UUID脚本多次切换吗

没太理解不同AB包同UUID脚本意思

多个AB包里面都有一个UUID的脚本
主包也有一个

如果可以的话能省很多事情

不太清楚,可能需要你自己尝试一下,如果是主包内的话需要重启才能生效,如果是AB包内的不需要重启

可以的话我给你demo你先试试
有效的话我再去买
话说cocos能退款吗

remoteBundle.zip (1.8 MB)