跳至主要內容

热更 bundle 脚本(不修改引擎)

muzzik大约 1 分钟笔记CocosCocosCreator热更

测试环境

版本:3.7.0

平台:[web-desktop-debug, android-debug-md5, android-release-md5]

注意事项

  • 重载 bundle 时不能在 bundle 内的场景
  • 重载前需要进行数据清理操作(例如定时器、节点池、监听的全局事件)
  • bundle 内的 ccclass 清理并没有很好的方法,所以是按照类名匹配,需要规范 @ccclass 装饰器的参数前缀

使用代码

/** bundle 脚本表 */
const bundle_script_tab: Record<string, any> = {};
/** js 系统 */
const system_js = self["System"];
/** 脚本缓存表 */
const script_cache_tab: Record<string, any> = system_js[Reflect.ownKeys(system_js).find((v) => typeof v === "symbol")];

// 初始化 bundle 脚本表
Object.keys(script_cache_tab).forEach((v_s) => {
	const current = script_cache_tab[v_s];
	const parent = script_cache_tab[v_s].p;
	const child = parent.d;

	if (!parent || !child || current.id !== parent.id) {
		return;
	}

	const name_s = parent.id.slice((parent.id as string).lastIndexOf("/") + 1);

	bundle_script_tab[name_s] = parent;
});

// 清理脚本缓存
{
	const bundle_root = bundle_script_tab[bundle_s];

	if (bundle_root) {
		bundle_root.d.forEach((v: { id: string }) => {
			delete script_cache_tab[v.id];
			delete system_js["registerRegistry"][v.id];
		});
		delete script_cache_tab[bundle_root.id];
		delete system_js["registerRegistry"][bundle_root.id];
	}
}

// 清理 ccclass
{
	const reg = new RegExp(`${bundle_s}(_|/)`);

	Object.keys(cc.js._nameToClass)
		.filter((v_s) => v_s.match(reg) !== null)
		.forEach((v_s) => {
			cc.js.unregisterClass(cc.js.getClassByName(v_s));
		});
}

// 清理 bundle 资源
{
	const bundle = cc.assetManager.getBundle(bundle_s);

	if (bundle) {
		bundle.releaseAll();
		cc.assetManager.removeBundle(bundle);
	}
}

// ... 加载 bundle

参数

  • bundle_s:bundle 名

实现参考

📣 觉得很赞?分享给你的朋友吧!