# 前言

前两天公司其他同事在推荐让试一试 WXAssetBundle,看看性能是不是真的有所提升,然后顺便就看到微信官方推荐使用 Addressables 系统进行资源加载 (其实之前就有瞄到这文档,只是当时项目重点不在这,所以没怎么注意)
当然微信虽然推荐 Addressables ,也提到如果自己进行维护管理的 AB 包 性能肯定会比 AA (Addressables) 包更好 ——

AA 包较大项目时生成的未压缩的 catalog 较大,加载效率低

所以微信推荐的原因是:

  • 学习使用曲线平滑,便于使用和维护,并且能快速切换想要的资源管理技术。

因此,就算我们还是在使用自己的包管理方式,先了解一下总无坏处:比如上面提到的 catalog,catalog 在 Addressables 中用来干什么的?

# 总览

Addressables 底层使用引用计数维护资源关系 (这是当然,我们自己的也是),被引用自动加载时,Unity 自动维护其引用计数。不过当我们显式加载可寻址资源时,就必须在使用完该资源后释放该资源了。

  • 另外,资源使用的内存只有在其所属的 AssetBundle 也被卸载后才会被释放 (与我们自己维护的一样)

所以,避免资源内存泄露的情况与使用自己的资源管理器是一样的:显式加载了记得释放。
另外需要注意:

  • 如果将 Resources 文件夹中的资源设置为可寻址,则 Unity 会将资源移出目录。可以选择自己将资源移动到项目中的其他文件夹,但不能将可寻址资源存储在 Resources 目录中。

注:Windows 的文件路径限制为 260 个字符

# 加载与卸载

自动加载依赖及引用计数
主要有以下几种方式:

  • AssetReferences
    • 一种资源引用,可以看做 可用于替换在 MonoBehaviour、ScriptableObject 定义的常规拖上去而使用的引用资源,例如对应 GameObject:AssetReferenceGameObject 或 AssetReferenceTexture 等,而 AssetReference 可认为是对应此前 Object 类型 (可以拖任何对象上去)
    • 此外,也可以使用 AssetReferenceUILabelRestriction 限制能拖上去指定标签的 Addressables 对象
    • 注:AssetReference.cs 中有详细列表
  • 通过地址 (路径) 加载
    • Addressables.InstantiateAsync(path)
    • Addressables.LoadAssetAsync<GameObject>(path)
  • 通过标签加载
  • IResourceLocation

与常规资源一样,加载之后需要对应卸载资源。

注:加载时也可以采用 async、await 异步方法,其 Load 方法中有 Task 属性

# 分组和标签

  • 分组用于组织具体内容,每个组可以有自己的打包设置 (如整个组单打为一个包,或分离打包、名字是否带 Hash 等)
    • 一个组打包成一个 Bundle
    • 组内每个资源都单独打成一个 Bundle
    • 组内同一标签的打成一个 Bundle
  • 同时也可以支持通过标签加载 (如果设置了标签的话)

# 资源清单 (catalogs)

即 catalogs 文件,Addressables 用来管理资源加载、依赖啥的
catalog_{日期}.hash

  • 检查 catalog.json 文件是否发生变化
  • 先下载这个,再决定是否下载 catalog_{日期}.json 文件

catalog_{日期}.json

  • 具体记录依赖关系啥的数据,Bundle 越多,该文件越大
  • 可以在 AddressableAssetSettings 中设置命名方式

可以自动加载,也可以手动加载,建议当然是手动加载比较好。Addressables 同样会缓存改文件,在 hash 发生变化时才会重新下载。

  • 哈希文件需要与目录位于同一位置并且具有相同的名称,路径的唯一区别是扩展名。

# 手动加载方式

  • Addressables.LoadContentCatalogAsync
  • 可选参数是否自动释放句柄,官方建议直接传 true 自动释放
  • 还可以手动调用 Addressables.CheckForCatalogUpdates 更新 (官方文档表示可以同时加载多个)

# catalogs 大小优化方式

  • 压缩:打包进 AssetBundle,当然这样做会导致加载时间增加 (有提供选项)
    • 注:只影响本地的 catalog,即与整包打包到 SteamingAssets 目录的那个
  • 禁止包含额外资源:每个分组设置上的 IncludeXXXXX
    • 这个选项得看情况设置,最新 Content catalogs 1.21.14 提供了 Disable built-in scenes and Resources 选项(我自己测试版本是 1.19 ,没这个选项,只有一些 IncludeXXXXX)

Manage catalogs at runtime | Addressables | 1.21.14

# 资源组类型

这里主要是指 『动态资源』、『静态资源』之分,其区别如下:

静态资源

Content Update Restriction 设置为 Cannot Change Post Release
动态资源
Content Update Restriction 设置为 Can Change Post Release

同时,基于是否设置为 Remote 而确定属于: 本地静态资源远程静态资源 还是 远程动态资源 三类中的一类。

注:在进行完整构建之后,如果只是更新打包不要修改该项,否则对更新会有影响

# 静态资源组

分为 本地静态资源远程静态资源

在资源发生变更后,可以通过菜单的 Tools->Check for Content Updates 将其自动设置到一个名为 ContentUpdate 的新分组中:


然后再使用 Build->Update Preview Build 就可以打出新组的包。

也就是说,更新打包时, Check for Content Updates 用于单独把修改过的资源挪到 UpdateContent 分组进行打包,这个分组默认设置就是 远程动态资源组

注:经测试,每次执行 Check for Content Updates 都会生成一个新的 UpdateContent 远程动态资源分组,分组重名则在后面加序号。

# 本地静态资源

Build&LoadPaths 设置为 Local 模式

在项目构建的时候 Addressables 会自动把资源拷贝到 SteamingAssets。

  • 试了下是真的 (PC 包)—— 另外 Remote (远程资源) 就不会跟随 Unity 打包进 SteamingAssets 目录。
  • 简单来说,似乎就是 Library\com.unity.addressables\aa 下的会跟随打包拷入 SteamingAssets 目录。
    • 注: 因为 Remote资源 是在 ServerData 目录,这个目录是没有的

# 远程静态资源

Build&LoadPaths 设置为 Remote 模式

远程静态资源一样会被复制到 ServerData 目录,这种就被称为 远程静态资源

  • 不过远程资源肯定都是没有就去下载,所以,暂时没弄明白 远程静态资源远程动态资源 相比,除了更新时会单独把修改过的资源挪到 UpdateContent 分组外,还有其它啥明显的区别和作用?
  • 感觉远程静态资源只会增加复杂性,所以还有其它在下没想到的设计考虑吗?


如上图所示,远程静态资源 (动态资源也一样) 包括其下载路径都会直接存储到本地的 catalog 数据中。

# 动态资源组

动态资源组只存在 远程动态资源 (都动态了肯定是远程下载了对吧?)
发生变更的资源会重新打包,同时直接覆盖掉原资源 (如果是附加了 Hash,则与原资源同级新增)。
如果想要进行资源更新,必须使用 Remote catalog ,即 远程动态资源组 ,上述静态资源组更新而自动创建的 UpdateContent 分组即为 Remote 动态资源组。

注:远程动态资源组确实很适合微信这种按需延迟下载使用的方式,使用流程跟正常的操作几乎一样方便。

# 测试

编辑器中提供了三种加载方式:

  • Use Asset Database:使用 AssetDatabase 进行加载,不用打 AssetBundle 即可测试
  • Simulate Groups:模拟 AssetBundle 信息进行加载,不用打 AssetBundle 即可测试,相比第一种方式会有更多一些信息
  • Use Exising Build:需要打包后加载,加载真实 AssetBundle 包

同时也直接提供了一个 Hosting 编辑器界面可用于本地打包后,开启一个模拟服务器测试远程加载资源情况,局域网内的设备也可以通过本地网络连测试资源的加载。

# EventViwer

需要勾选设置项的 Send Profiler Events

这个界面初步看来,可以查看加载的 AssetBundle 对象及其依赖啥的。其它功能还待了解。

# Analyze

资源分析界面,可用来查找重复资源引用之类的,可以方便地将重复资源直接设置到一个新分组。

# 注意

  • addressables_content_state.bin
    • 更新打包时需要用来对比 (Update Preview Build)
  • Update Restrictions
    • 区分静态资源和动态资源
    • 打包之后不要变更

# 总结

过了一番流程之后,感觉官方的 Addressables 的使用确实已经比较方便,特别是连模拟加载及自带服务器模拟都提供了。
至于最开始前言提到的 "catalog" 作用,也知道了这该是属于 Addressables 的清单文件,记录了资源依赖之类的关系,必须首先加载才能进入后续流程。
当年 (记得好像是 2017 年?) 就听说官方要出新的资源管理方式,就不想去研究 AssetBundle,结果最后还是搞起了 AssetBundle,直到现在才过了一遍官方这个新的 Addressables... 如果以后我自己搞新项目,一定得实际尝试一番。

注:Addressables 是开源的。

# 参考文档

Design/UsingAddressable.md · Ocean/minigame-unity-webgl-transform - Gitee.com
Design/ResourcesLoading.md · Ocean/minigame-unity-webgl-transform - Gitee.com
Configure your project to use Addressables | Addressables | 1.21.14
Addressables 之远程内容分发
Addressables 之配置
使用 Addressable Assets System 进行资源按需加载
Unity - Addressables 项目总结(一):基础工作流