【unity】使用QFramework开发微信小游戏的总结

发布时间 2023-09-06 18:52:15作者: AshScops

前言

在使用Unity + QFramework开发微信小游戏的过程中遇到了一些问题,在此记录下来,方便查阅参考。

主要问题

主要问题是框架的资源加载方式和小游戏要求不一致。

QFrameworkUIKitAudioKit依赖于ResKitResKit底层是从本地磁盘上读取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:// 的原理是一样的。

--摘自凉鞋的笔记

除此之外,还有一些小的关联项:

  1. AB包之间可能存在依赖关系,QFramework的解决方案是:生成AB包时,自动生成一个.bin文件,加载时从该文件获取依赖关系,而非从主包中获取。自定义加载依赖包的方式也可。我的方案是将.bin文件上传服务器,魔改框架,使ResKit异步初始化时从服务器下载。

  2. 由于打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))。

问题与注意事项

  1. 注意修改原框架时,在修改处打上类似注释,方便日后维护:

    //Update by xxx //修改 //魔改

  2. 引入微信小游戏转换工具后,变得只能打WebGL的AB包了,其他平台的AB包一概打不了。若要打其他平台的AB包,则需临时移除转换工具。

  3. [尽可能使用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的引用计数管理资源。

  4. 若要解决多平台资源加载方式不一的问题,则业务侧在加载资源时要统一向加载方式最受限的平台看齐(统一方案为UnityWebRequest异步加载),利用Unity宏进行多路测试无误后方可导出。

  5. 虽然我的解决方案实机测试有效,但可能是服务器没开启CDN的原因,审核那边总是加载超时给我打回,最后只能妥协,把所有资源全放进Resources中,压进首资源包,这才得以通过审核。

参考资料

[凉鞋的笔记](Unity 游戏框架:资源管理神器 ResKit - 凉鞋的笔记 - 博客园 (cnblogs.com))

[微信小游戏官方文档](minigame-unity-webgl-transform/Design/UsingAssetBundle.md at main · wechat-miniprogram/minigame-unity-webgl-transform (github.com))