跳转至

Addressables 远程资源更新

起因

第一次用 Addressables 做远程更新时,我以为把新打出来的 Bundle 覆盖到 CDN 上就行了。结果客户端还在读旧 Catalog,资源地址没变,但文件内容已经换了,最后出现加载到一半失败、缓存和清单对不上的情况。

后来才理清:资源文件、Catalog 和客户端缓存是三条独立的时间线,更新时必须一起考虑。

三个容易混淆的东西

对象 作用 更新时要注意
AssetBundle 实际资源数据 路径最好不可变,按构建版本分目录
Catalog 地址、依赖和 Bundle 的映射 客户端要主动拉取新版本
Profile 构建路径和加载路径的变量 本地路径与远程路径不要混用

简单来说,Catalog 决定“去哪拿”,Bundle 是“拿到的内容”。只换 Bundle 不换 Catalog,客户端通常不知道新文件在哪里。

分组不要按文件夹来

Addressables 的 Group 更适合按“会不会一起加载、一起更新、一起回退”来分。1 例如:

  • scene-common:多个关卡共用,更新频率低。
  • battle-01:一个关卡或一个玩法模块。
  • ui-activity:活动资源,可能每周更新。
  • local-tutorial:跟随包体发布,不走远程。

把同一个功能的贴图、预制体和配置放在同一个 Group 里,更新时更容易控制下载量。按 Textures、Prefabs 这种文件夹分,最后往往会把所有模块绑在一起。

客户端更新流程

启动时先初始化,再更新 Catalog,最后按 Label 或 Address 下载依赖:

public async Task UpdateRemoteContentAsync(string label)
{
    var init = Addressables.InitializeAsync();
    await init.Task;
    Addressables.Release(init);

    var update = Addressables.UpdateCatalogs(false, null);
    await update.Task;
    Addressables.Release(update);

    var sizeHandle = Addressables.GetDownloadSizeAsync(label);
    var size = await sizeHandle.Task;
    Addressables.Release(sizeHandle);

    if (size == 0)
        return;

    var download = Addressables.DownloadDependenciesAsync(label);
    try
    {
        await download.Task;
    }
    finally
    {
        Addressables.Release(download);
    }
}

GetDownloadSizeAsync 只计算还没进缓存的资源,适合在加载界面显示体积。DownloadDependenciesAsync 默认不会自动释放 Handle,所以这里手动 Release。

发布目录按版本隔离

远程加载路径可以配置成:3

https://cdn.example.com/aa/{BuildTarget}/{BuildVersion}

BuildVersion 是自定义 Profile 变量,每次构建生成一个新值,例如 2026.11.14-01。每次发布上传到新目录,CDN 上的旧目录先保留。需要回退时,把客户端读取的 Catalog 指回旧版本就行,不用重新打包。

本地构建路径和远程加载路径要分开:

LocalBuildPath   = Library/Addressables/{BuildTarget}
LocalLoadPath    = {UnityEngine.AddressableAssets.Addressables.RuntimePath}/{BuildTarget}
RemoteBuildPath  = ServerData/{BuildTarget}/{BuildVersion}
RemoteLoadPath   = https://cdn.example.com/aa/{BuildTarget}/{BuildVersion}

这样可以先把内容构建到本地,再由发布脚本上传,避免编辑器直接写 CDN。

内容更新不是普通重建

如果线上已经有玩家,直接重新 Build 全部内容会生成新的 Catalog,但旧包里的静态资源可能和新包不兼容。Addressables 提供了 Content Update 流程:先比较上次构建,再只打包发生变化的组,同时检查静态内容的限制。2

实际操作时要注意:

  • 不要修改已经发布的 Address 或 Group 名,除非准备好迁移。
  • 更新包和完整包分别验证,不能只测编辑器里的 Play Mode。
  • Catalog 下载成功不代表 Bundle 下载成功,两个失败要分开统计。
  • 活动资源可以预下载,但不要在战斗过程中突然开始大文件下载。
  • 旧 Catalog 和旧 Bundle 至少保留一个版本的回退窗口。

下载放在加载界面

可以在登录或主城阶段完成 Catalog 更新,把实际资源下载放到玩家进入副本前的加载界面。这样登录流程不会因为 CDN 慢而卡太久,进入战斗时也不会临时读远程文件。

另外,建议在启动时关闭自动 Catalog 更新,改成显式调用 UpdateCatalogs。自动更新失败时不容易提示玩家,也不方便记录当前使用的是哪个版本。