外观
Stage03|Runtime Objects & Assets
Lesson034|Asset Bundle、远程资源、CDN 与版本管理
Tags: #Creator2.x #Stage03 #AssetBundle #RemoteAsset #CDNDifficulty: ⭐⭐⭐⭐☆
真实问题:CDN 已上传新活动,玩家为什么仍看到旧界面
运营把 summer Bundle 的新文件覆盖到 CDN。开发机清缓存后正常,线上玩家却分成三类:
- 有人看到新活动;
- 有人仍看到旧图片;
- 有人 Bundle 配置是新的,但依赖图片 404。
这不是简单的“CDN 缓存没刷新”。远程 Bundle 是一条带版本的发布协议:
text
客户端内置入口
→ Bundle 版本/配置
→ CDN URL
→ 配置与资源文件
→ 本地下载缓存
→ Asset 依赖解析
→ 业务实例化任一层新旧不一致,都可能形成混合版本。
一、本课目标
随着资源量增长,不能把所有资源都和首包一起加载。本课理解:
- Asset Bundle 的组织价值。
- 远程资源的加载边界。
- CDN 和版本清单的作用。
- 为什么资源更新必须考虑缓存和回滚。
二、Bundle 解决什么问题
可以把 Bundle 理解成可独立管理的一组运行时资源:
text
首包
├── 基础 UI
└── 启动场景
Bundle: level_01
Bundle: activity_summer
Bundle: character_skin它可以帮助:
- 延迟加载低频内容。
- 拆分首包和更新包。
- 按功能组织依赖。
- 控制资源下载和释放边界。
具体 API 和构建配置以 Creator 2.4.x 项目为准,不要把 3.x Bundle API 直接套用到 2.x。
三、远程资源的完整链路
text
客户端请求资源地址
↓
CDN / 文件服务器
↓
下载资源和依赖
↓
校验版本或哈希
↓
本地缓存
↓
运行时 Loader 解析
↓
业务使用失败点比本地资源多:
- 网络不可用。
- CDN 节点异常。
- 版本清单不一致。
- 下载中断。
- 本地缓存损坏。
- 依赖资源版本不匹配。
四、版本清单为什么重要
资源发布通常需要一个版本描述:
text
资源名
版本号
文件哈希
大小
依赖版本
下载地址客户端通过清单判断:
text
本地是否已有
是否需要更新
缓存是否完整
依赖是否兼容只改文件名或时间戳而没有一致性校验,容易让客户端拿到新旧资源混合的状态。
五、缓存和 CDN 的关系
text
客户端缓存
↓ 未命中
CDN 边缘节点
↓ 未命中
源站发布新资源时要考虑:
- URL 是否带版本号或内容哈希。
- CDN 缓存多久刷新。
- 旧版本客户端能否继续访问旧资源。
- 回滚时旧资源是否仍保留。
资源更新不是“上传文件”这么简单,而是客户端、缓存和服务端的协议。
六、远程资源的生命周期
text
未下载
→ 下载中
→ 本地缓存
→ 解码加载
→ 页面使用
→ 页面关闭
→ 仍可能被其他页面使用
→ 安全释放远程下载完成不等于 GPU 纹理已经准备完成;本地缓存文件存在也不等于运行时对象不会再次解码。
七、案例:活动资源包
text
主包:基础 UI、登录、大厅
活动 Bundle:活动场景、图集、音频、配置进入活动:
text
读取活动版本清单
→ 检查本地缓存
→ 下载缺失依赖
→ 加载活动 Scene
→ 显示活动页面退出活动:
text
关闭页面
→ 取消监听和异步回调
→ 解除对象引用
→ 按使用关系释放资源八、常见误区
误区一:Bundle 就是一个压缩 ZIP
它更重要的是资源组织、依赖和加载边界,具体产物由构建系统决定。
误区二:CDN 更新文件后所有客户端立即拿到新版本
本地和 CDN 缓存可能继续返回旧资源。
误区三:下载成功就代表资源可使用
还可能需要校验、解码、依赖加载和运行时对象创建。
误区四:远程资源不需要释放
下载和运行时缓存都可能占用磁盘或内存。
九、练习与答案
练习
- Bundle 的主要价值是什么?
- 远程资源链路比本地资源多哪些失败点?
- 版本清单需要描述什么?
- 为什么 URL 版本化有助于缓存更新?
参考答案
- 按功能拆分资源,支持延迟加载、更新和释放边界。
- 网络、CDN、版本、下载完整性、缓存和依赖兼容问题。
- 版本、哈希、大小、地址和依赖信息。
- 新 URL 避免旧缓存继续命中同一个地址。
Bundle 的三个身份不要混淆
业务模块身份
例如 summer-event,表达活动模块。
构建版本身份
构建输出中的 hash、版本参数或清单,帮助区分内容版本。
远程地址
CDN 上实际提供配置和资源的 URL。
错误发布常把“相同 Bundle 名”当成“相同内容”。客户端需要拿到一组内部一致的配置与资源,不能让入口清单指向新配置,而新配置的一部分依赖仍未上传。
Creator 2.4.x 本地实验:先验证 Bundle 边界
Bundle 配置、资源移动和构建通过 Creator 编辑器完成。不要手工伪造
.meta或直接修补build/。
准备
- 在 Creator 中创建一个
bundle-lab资源目录。 - 通过 Inspector 将它配置为 Asset Bundle。
- 放入一个 Prefab 和一张由 Prefab 引用的图片。
- 创建入口场景,但不要静态引用该 Prefab。
- 创建
BundleProbe.ts。
ts
const { ccclass, property } = cc._decorator;
@ccclass
export default class BundleProbe extends cc.Component {
@property(cc.Node)
container: cc.Node = null;
private generation = 0;
openBundlePanel() {
const id = ++this.generation;
cc.assetManager.loadBundle(
'bundle-lab',
(bundleErr, bundle) => {
if (bundleErr || id !== this.generation) {
cc.error('[bundle] load bundle failed', bundleErr);
return;
}
bundle.load(
'panel',
cc.Prefab,
(assetErr, prefab: cc.Prefab) => {
if (assetErr
|| id !== this.generation
|| !cc.isValid(this.node)) {
cc.error('[bundle] load asset failed', assetErr);
return;
}
this.container.addChild(cc.instantiate(prefab));
cc.log('[bundle] panel ready');
}
);
}
);
}
closePanel() {
this.generation++;
this.container.removeAllChildren();
}
}实验 A:入口与内部资源分开失败
先故意写错 Bundle 名,再写对 Bundle 名但写错内部路径。
预期得到两类不同错误:
text
loadBundle 失败:入口、名称、位置或配置问题
bundle.load 失败:Bundle 已存在,但内部路径/类型/依赖有问题诊断日志必须保留这两个阶段,不能统一显示“资源失败”。
实验 B:关闭页面不等于取消共享下载
打开后立即关闭,generation 使回调失效。观察 Bundle/Asset 底层任务仍可能完成。这与 L031 的竞态模型一致。
实验 C:构建验证
通过 Creator Build 面板构建一个测试目标,检查构建日志与 Bundle 输出是否存在。不要手改输出内容;修改源配置后重新构建。
远程发布必须具有原子性
理想发布顺序:
text
1. 生成不可变版本目录
2. 上传全部配置与资源
3. 从外部网络校验每个文件
4. 校验 hash、大小和依赖完整性
5. 最后发布指向新版本的入口
6. 监控错误率
7. 保留旧版本供回滚不要先覆盖“latest”配置,再慢慢上传依赖。那会产生一个客户端必然能观察到的不完整窗口。
不可变 URL 示例:
text
cdn.example.com/bundles/summer/2026.08.16/...版本入口只负责选择哪一目录。旧客户端继续访问旧目录,新客户端访问新目录,CDN 缓存不会把不同内容混在同一 URL 下。
缓存要回答三个问题
缓存键是什么
只用 Bundle 名,还是包含版本/hash?
谁判定过期
客户端清单、HTTP Cache-Control、CDN 刷新还是业务版本?
回滚怎样发生
入口切回旧版本后,客户端是否还能访问旧资源?本地是否错误复用了新配置?
“让用户清缓存”不能作为正式版本策略。
真实项目故障:配置成功但图片 404
事故链
text
新 config.json 先发布
→ 配置引用 texture.abcd123
→ 图片文件仍在上传
→ 一部分边缘节点已缓存新配置
→ 客户端请求尚不存在的新图片
→ 页面半新半旧诊断证据
- 客户端 Bundle 名与版本;
- config URL、状态码和响应 hash;
- 失败资源的完整逻辑路径与最终 URL;
- CDN 请求 ID/边缘节点;
- 本地缓存命中情况;
- 发布流水线各文件到达时间。
修复
先上传不可变资源并校验,最后切入口;失败时入口回滚。资源版本目录在支持周期内不可删除。
安全与可靠性边界
远程资源不仅有可用性问题,还要考虑:
- HTTPS 与证书;
- 配置/文件完整性校验;
- 非法路径和内容注入;
- 下载大小上限;
- 超时、重试和退避;
- 磁盘缓存预算;
- 蜂窝网络策略;
- 最低客户端兼容版本。
重试必须有上限和退避,不能在 update 中持续发请求。
版本边界与官方入口
本课以 Creator 2.4.x Asset Bundle 为主。Bundle 构建选项、远程地址和缓存行为应以当前 2.4.x 小版本及目标平台文档为准。
深化练习与答案
- 为什么同一 URL 直接覆盖文件容易产生旧内容? 浏览器、本地和 CDN 都可能缓存该 URL;若内容可变,版本身份与缓存键不一致。
- 为什么入口文件应最后发布? 入口一旦指向新版本,客户端就可能请求所有新依赖;最后发布能保证被引用内容已经完整可用。
- Bundle 下载成功后为什么 Prefab 仍可能失败? Bundle 配置可用不代表内部路径、类型和所有依赖都可用,必须分阶段处理错误。
- 回滚为什么要求保留旧版本目录? 入口切回只能选择旧版本,若旧资源已删除,回滚只是把客户端指向另一组 404。
十、本课总结
text
Bundle 管理资源集合和加载边界。
远程资源需要清单、缓存、校验和回滚策略。
CDN 是分发链路,不是版本管理本身。
下载、解码、运行时加载和资源释放是不同阶段。十一、下一课预告
text
Lesson035|为什么 destroy 节点不等于释放资源?