【unity】使用QFramework开发微信小游戏的总结
前言
在使用Unity
+ QFramework
开发微信小游戏的过程中遇到了一些问题,在此记录下来,方便查阅参考。
主要问题
主要问题是框架的资源加载方式和小游戏要求不一致。
QFramework
的UIKit
和AudioKit
依赖于ResKit
,ResKit
底层是从本地磁盘上读取AB包的。
而[微信小游戏官方文档](minigame-unity-webgl-transform/Design/UsingAssetBundle.md at main · wechat-miniprogram/minigame-unity-webgl-transform (github.com))中提到:
小游戏环境不支持assetbundle本地加载......
小游戏因其平台特殊性,需要保证加载速度,因此我们在底层对bundle文件做了缓存,开发者无须自己实现缓存。
游戏逻辑还是按照未缓存需要从网络下载去编写,插件底层会判断是否已有缓存。若未缓存则缓存此bundle;若已缓存,则返回缓存文件,实际不会发起网络请求。
可参见资源缓存与淘汰
资源缓存与更新的不同,会导致APP与小游戏不同的加载流程
- 常见APP AssetBundle使用方式:
检查更新-->下载更新全量资源-->写入文件系统-->运行时LoadFromFile
- 微信小游戏 AssetBundle使用方式
打包ab时文件名带hash-->UnityWebRequest按需下载并使用资源
在业务侧看来:总是使用异步接口从远程下载并使用,底层资源的缓存与更新已由适配层自动完成,游戏不再直接读写文件系统。
我们需要根据微信小游戏的要求,来自定义QFramework
中的资源加载方式,也就是接下来解决方案中所述。
解决方案
自定义Res
来下载服务器资源,并提取加载方式,将其作为一个切面来管理(AOP)。
自定义Res
可参考以下说明:
如果想加载 Resources 目录下的资源,代码如下所示:
var someObjPrefab = loader.LoadSync("resources://someObj");
当然也可以扩展成支持加载网络资源等。
这里关键的一点是 resources:// 这个前缀。和 https:// 或 http:// 类似,是一个路径,和 www 的 file:// 的原理是一样的。--摘自凉鞋的笔记
除此之外,还有一些小的关联项:
-
AB包之间可能存在依赖关系,
QFramework
的解决方案是:生成AB包时,自动生成一个.bin文件,加载时从该文件获取依赖关系,而非从主包中获取。自定义加载依赖包的方式也可。我的方案是将.bin文件上传服务器,魔改框架,使ResKit
异步初始化时从服务器下载。 -
由于打AB包时要带Hash值:
打包bundle时,请使用如下参数
- 【重要】BuildAssetBundleOptions.AppendHashToAssetBundleName:bundle带上hash。在小游戏底层对bundle做缓存及缓存淘汰时,hash是重要依据,请查阅小游戏资源缓存
- BuildAssetBundleOptions.ChunkBasedCompression:LZ4压缩方式,加载速度和包体大小更均衡。
- 如非需要新老Unity引擎版本兼容,请使用DisableWriteTypeTree提升加载速度与降低内存。
而
QFramework
打AB包时生成的.bin文件中的AB包名,默认不会带上这个Hash后缀。我的解决方案是遍历AB包,带Hash后缀的AB包名存入txt文件,并上传服务器,游戏初始化时从服务器下载,下载AB包时从该文件匹配,然后拼接URL即可。更好的方案可能是让.bin文件中的AB包名带上Hash后缀,不过还未验证是否可行。
另外,QFramework
打AB包时生成的.bin文件,实际上不止记录AB包的依赖关系,还记录了每一个资源对应哪个AB包名。这也是QFramework
加载资源时,在业务侧无需传入AB包名的原因。具体见[凉鞋的笔记](Unity 游戏框架:资源管理神器 ResKit - 凉鞋的笔记 - 博客园 (cnblogs.com))。
问题与注意事项
-
注意修改原框架时,在修改处打上类似注释,方便日后维护:
//Update by xxx //修改 //魔改
-
引入微信小游戏转换工具后,变得只能打WebGL的AB包了,其他平台的AB包一概打不了。若要打其他平台的AB包,则需临时移除转换工具。
-
[尽可能使用
Unload
](minigame-unity-webgl-transform/Design/UsingAssetBundle.md at main · wechat-miniprogram/minigame-unity-webgl-transform (github.com)):- 当bundle从资源服务器下载并使用,会经历多次内存分配: 浏览器HTTP对象-->拷贝到WASM临时内存-->Unity ab内存文件(略大于ab本身体积, 相对于APP常用的LoadFromFile,WebGL这部分开销是额外的)
- 当HTTP对象dispose之后,Unity ab内存文件
- 当ab.Unload时,Unity ab内存文件释放
因此,最佳实践是业务应该尽可能早地使用ab.Unload(false),自行维护Asset的引用计数管理资源。
-
若要解决多平台资源加载方式不一的问题,则业务侧在加载资源时要统一向加载方式最受限的平台看齐(统一方案为UnityWebRequest异步加载),利用Unity宏进行多路测试无误后方可导出。
-
虽然我的解决方案实机测试有效,但可能是服务器没开启CDN的原因,审核那边总是加载超时给我打回,最后只能妥协,把所有资源全放进Resources中,压进首资源包,不再从AB包中加载,这才得以通过审核。
参考资料
[凉鞋的笔记](Unity 游戏框架:资源管理神器 ResKit - 凉鞋的笔记 - 博客园 (cnblogs.com))