示例工程:
https://github.com/sss0vvv/CocosCreatorHotUpdate.git
macOS Big Sur 11.1
Cocos creator 2.4.3
Xcode 12.3
Android Studio 4.1
NodeJs
XAMPP
以下 Asset Bundle 简称 AB.
调用cc.assetManager.loadBundle加载AB时可传入参数version指定某个版本,如果该版本已经存在于可读写路径下的gamecaches则从本地加载,否则先从远程服务器下载到本地再加载.
gamecaches/cacheList.json 记录了本地缓存的文件.
{
"files": {
"http://192.168.69.197:8089/dashboard/hotTest/remote/ABLobby/index.808a1.js": {
"bundle": "ABLobby",
"url": "ABLobby/11111610276469253.js",
"lastTime": 1616276601323
},
},
"version": "1.1"
}
Asset Bundle官方指引
https://docs.cocos.com/creator/manual/zh/asset-manager/bundle.html
新增一个大厅模块、两个子游戏模块, 均设置为asset bundle , 配置为远程包 . 如果存在AB引用另一个AB的情况, 被引用的AB 设置更高优先级. 示例中 ABSubgame2 引用了 ABSubGame1 和 ABLobby 中的文件和代码.
let moduleMagObj = cc.instantiate(this.ModuleMagPreFab)
moduleMagObj.parent = this.node
window._G_moduleMag = moduleMagObj.getComponent("ModuleManager")
_G_moduleMag.initCom({
useHotUpdate : true , // 是否启用热更新
})
//-------------------
// 复制包内模块到可读写路径下,避免首次加载模块时从远程完整拉取
_G_moduleMag.execUnpackage(()=>{
_G_moduleMag.reqVersionInfo(()=>{ // 获取最新版本
let loadAb = ["ABLobby"]
// loadAb = ["ABLobby", "ABSubGame1", "ABSubGame2"]
_G_moduleMag.hotUpdateMultiModule(loadAb,()=>{ // 更新模块到最新版本
_G_moduleMag.addModule("ABLobby", (moduleObj)=>{ // 加载模块
let abObj = moduleObj.getABObj()
abObj.load('root/Scene/LobbyRoot', cc.Prefab, (err, prefab)=>{ // 使用模块资源
//...
})
})
})
})
})
// 定时检测更新
// _G_moduleMag.reqLoopVersionInfo()
执行构造HotRes_macos.sh, 构建出来的remote将被拷贝到hotRes目录下, 同时verconfig.json中的版本号也将被更新.
将hotRes目录下文件上传到下载服务器,注意服务器上保留remote这级目录, 我配置的下载地址"http://192.168.69.197:8089/dashboard/hotTest/" .
执行构造PKgamecaches_macos.sh, 构建出来的remote将被拷贝到assets/PKgamecaches目录下, 指定的模块将会打到发布包里.
分别测试模块随包发布和模块完整下载
示例使用Xcode模拟器, 如果跑模拟器时遇到找不到文件的日志, 将main.js 和 src 从Xcode移除引用再从文件夹拖进来.
将可读写路径下文件清除、将 PKgamecaches 删除, 启动模拟器搜索**[HotUIHelper]**日志查看更新进程.
这是我这里的,实际路径要跑起来看日志.
JS: [HelloWorld] jsb_writable_: /Users/svsv/Library/Developer/CoreSimulator/Devices/8863F5D0-DDE1-472A-8655-4A8E46EF0F37/data/Containers/Data/Application/126C4155-5508-430B-9439-34B7261643C3/Documents/
将 /build/jsb-link/assets/ 下的src, assets, main.js三个文件覆盖到win32Example_exe文件夹, 执行 hot_example.exe启动游戏, 单击键盘TAB键保存Log日志到可读写路径下 alogRecord.txt .
ModuleMagPreFab.prefab 用于挂载热更新代码.
assets/Script/ModuleMag/ 包含了热更新涉及的代码.
ModuleCom.js :
一些常用的方法
ModuleConst.js :
一些参数定义
HotUIHelper.js :
展示更新过程中的提示信息
Module.js :
模块类,
4.1负责加载AB实例
let abUrl = "http://192.168.69.197:8089/dashboard/hotTest/"+abName
cc.assetManager.loadBundle(abUrl, {version:"1.1.1"}, (err, bundle)=> {
//这里仅仅下载到AB构建出来的 index.e350c.js 和 config.e350c.json
})
4.2 下载对应AB版本的资源.使用preloadDir下载根目录root下的文件
bundle.preloadDir("root", (finish, total, item)=>{
}, (error, items)=>{
})
4.3 打开AB配置文件 config.e350c.json 可以看到, 项目中使用到的AutoAtlas构建出的png文件并没有配置到里面.
所以preloadDir是不会去下载AutoAtlas图集文件的.
通过 bundle._config.assetInfos._map 可以看到自动图集的项是没有path字段的,把这些项筛选出来用cc.assetManager.preloadAny下载.
cc.assetManager.preloadAny(autoAtlas, { __requestType__: 'url', type: null, bundle: this._abObj.name },
(finish, total, item)=>{
}, (error, items)=>{
}
);
ModuleManager.js :
模块管理类, 负责构建 Module , 以及 Module 新版本检测.
游戏启动后从远程请求版本配置文件verconfig.json, 对比本地的版本信息, 发现新版本则交给 Module 下载更新, 更新完成后替换本地版本号.
UnpackageHelper.js :
6.1 负责将随包发布的AB复制到可读写路径下gamecaches .
6.2 为了避免新安装的客户端cc.assetManager.loadBundle加载远程AB时,在可读写路径下gamecaches找不到该版本而从服务器完整下载AB, 所以将随包AB复制到可读写路径下, 以达到加载AB逻辑一致的目的.
verconfig.json :
版本控制配置文件.
设置AB版本号、优先级和依赖关系.
{
"clientMin": "1.0.0",
"modules": {
"ABLobby": {
"resVersion": "808a1",
"showVer": "1.0.127",
"priority": 6,
"depend": [ ]
},
"ABSubGame1": {
"resVersion": "e350c",
"showVer": "1.0.127",
"priority": 5,
"depend": [
"ABLobby"
]
},
"ABSubGame2": {
"resVersion": "3de91",
"showVer": "1.0.127",
"priority": 4,
"depend": [
"ABSubGame1"
]
}
}
}
保留 PKgamecaches , 启动模拟器搜索**[HotUIHelper]**日志查看更新进程.
每个模块中的资源需放在 root 文件夹下
需要跑热更新时,初始化 ModuleManager 传入 useHotUpdate(true) .
请不要用Creator自带模拟器(资源结构不同)跑热更新,可以使用Xcode模拟器或者安卓真机调试热更新.
修改 makePKgamecaches.js 中的 hotUrl 为你的资源下载地址. 修改 ModuleConst.js 中的 hotUrl 为你的资源下载地址.
hotRes上传到资源下载服务器,需保留remote这级目录.
1. 热更新模块本身并不支持热更新,功能稳定后这个需求并不是很强烈,如需支持创建一个 Asset Bundle, 把热更模块移过去也可以实现.
3. 已加载的模块在进行热更新后需要重新进入游戏 cc.game.restart() , 未加载的模块热更后则不需要重启.
4. 没有统计热更新文件大小.