1. Addressable远端加载到底解决什么问题
先聊点实际的。做Unity项目,尤其是手游和端游,资源管理永远是绕不过去的一道坎。早年大家用AssetBundle,用原生AB方案就得自己写依赖分析、打包规则、版本管理和加载管理器,一套搞下来没几万行代码打不住,而且不同项目AB方案很难复用,基本是“一个项目一套轮子”。
后来Unity官方推出了Addressable Asset System,也就是我们常说的Addressable。它的核心思路是:把“资源怎么存、怎么加载、怎么管理生命周期”从业务代码里抽象出来,用一套可配置的资产寻址系统去统一处理。你用字符串或者Addressable资产引用去加载资源,底层是AssetBundle还是Resources,调用方根本不需要关心。
而“远端加载资源”这个能力,才是Addressable真正拉开差距的地方。简单说,它允许你把一部分资源(角色模型、场景、关卡数据、UI图集,甚至代码热更用的二进制文件)放到远程服务器上,客户端运行时按需下载、缓存、加载和更新。配合Group的Local/Remote分组,你就能实现“首包只带核心资源+界面,大头内容全部走远端”的发布模式。
这篇文章适合谁看呢?
- 正在搭Unity新项目,考虑要不要上Addressable的团队
- 已经在用AssetBundle原生方案,想换到Addressable但不知道怎么迁的开发者
- 已经用了Addressable,但只用过本地加载,想让资源走CDN做热更的工程师
这篇文章我会结合一个实际的远端加载Demo来说,涉及工程配置、分组策略、Profile设置、代码链路、常见报错排查和踩坑记录。另外最近群里很多人聊yooasset和addressable的选型对比,我最后也会用一节的篇幅讲讲我对这两个方案的看法,尽量客观。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体设计思路:先搞清楚Addressable是怎么运作的
2.1 核心链路:资产地址、目录、Bundle、远端
要理解Addressable远端加载,你得先抓住一条主线。整个系统的运转逻辑可以概括为:资产地址到AssetBundle的映射,AssetBundle到远端路径的映射,运行时按地址查目录并加载对应Bundle。
具体拆开来看:
- 地址(Address):你在代码里用的字符串,比如
Assets/Prefabs/Player.prefab。 - Addressable Asset Settings(AAS配置):全局配置文件,管理所有Group、Profile、Catalog设置。
- Group(分组):把资产划分到不同组,每个组独立决定构建路径、加载路径、压缩方式。
- Content Catalog(内容目录):运行时最重要的文件,记录所有资源地址和Bundle之间的对应关系,以及依赖信息。
- AssetBundle:最终打包产物,本地层和远端层的Bundle文件路径由Group配置决定。
- Profile(配置文件):定义了一套变量,比如LocalBuildPath、RemoteBuildPath,用来拼接具体的加载路径。
这段链路里,任何一个环节没对应上,都会导致加载失败。我见过太多人AssetBundle加载失败的报错,最后发现是Group的Build Path和Load Path没配对。尤其是远端加载,一旦涉及CDN路径和本机打包缓存路径不一致,就很容易翻车。
2.2 分组策略:Local组与Remote组该怎么划
用Addressable做远端加载,第一件事不是写代码,而是规划分组。分组划得好,后面省心一半。
我的建议是:按“更新频率”和“首包必要性”两个维度来划分。
- Local Group:存放核心UI、引导流程、必玩的玩法入口,这些放在首包。
- Remote Group:存放后续活动内容、高等级美术资源、时装、地图、离线包资源,这些走远端。
Dimension是“条目”,我用的是旧版命名体系,新版叫“Labels”。实际配置时要注意:
- Local组的Load Path一般用
{UnityEngine.AddressableAssets.AddressableAssetSettings.LocalLoadPath},对应到StreamingAssets。 - Remote组的Load Path建议配置成你的CDN地址模板,比如
https://your-cdn.com/addressable/{platform}。
还有一个很容易忽略的点:Remote组建议开启Build Remote Catalog,这样远端目录会生成catalog.json。运行时如果设置了自动检查目录更新,客户端能拉取到最新目录,才知道远端有哪些新的Bundle版本。
2.3 运行时的加载分支
当你在代码里调用Addressables.LoadAssetAsync时,系统内部大致做这么几件事:
- 查目录(catalog),找到Address对应的Bundle信息。
- 判断这个Bundle在本地还是远端。
- 本地直接读取,远端检查是否已经下载并缓存,如果没缓存则先下载。
- 加载Bundle,解析依赖(AssetBundle之间的引用关系也会被自动处理)。
- 从Bundle中实例化资源返回给调用方。
这一步里藏着一个很重要的经验:远端Bundle默认不自动下载,除非资源属于一个被标记为“Preload”的Group,或者你调用了Addressables.GetDownloadSizeAsync和Addressables.DownloadDependenciesAsync。 这就意味着你需要在代码里实现“检测到远端资源未下载→弹下
