Unity 热更资源检出与校验:一次三周迭代的完整记录(catalog 驱动 / 快路径 / 原子提交 / 拷贝与下载分离)
目录一、这段流程要解决什么问题二、四条核心设计原则原则 1:以最终 catalog 为唯一权威原则 2:catalog 落地 = 本次更新成功(原子提交)原则 3:信任上一次成功提交,能不算就不算原则 4:做减法,而不是加机制三、迭代时间线:关键节点与事件三个最值得复盘的节点四、最终架构:九步流水线各步职责一个容易被忽略的工程决定:编辑器里全部跳过五、关键机制详解5.1 归属校验:bundle 到底该从哪儿来5.2 失败分类:这是全文最重要的一张表5.3 回退路径5.4 APK 变更:签名变化就整体重来5.5 版本号与提交点绑定5.6 报错方式本身也是设计5.7 一些具体的常量5.8 已知取舍:MD5 是整份读进内存的六、最后一公里:拷贝不是下载根因不是性能,是职责拍板记录数据移交:同一张表,原地移除防呆:允许来源白名单为什么不是其它做法七、复盘:几条可复用的经验八、小结项目背景:Unity 2022.3.62f2 手机 Roguelike。代码热更走 HybridCLR(Assembly-CSharp.dll作为热更 DLL 下发),资源热更走 Addressables。启动器Launcher位于 AOT 程序集(Launcher.asmdef),在热更 DLL 加载之前运行——本文讲的就是这一段"上不着村下不着店"的资源同步链路。一、这段流程要解决什么问题手游热更最容易被低估的部分,不是"下载文件",而是判断该下载什么、什么时候算成功、中断了怎么办。我们的启动资源同步要同时面对三种来源:来源说明典型体积StreamingAssets随包基线资源,首装包内就有大(绝大多数 bundle)hotfix远端热更包上传的增量 bundle / 代码包小(通常几 MB)baseAPKBundleUrl远端远端基线来源,仅当包内没有基线时使用中~大新用户首次启动时,需要补齐的 bundle 里绝大多数是包内基线拷贝(StreamingAssets→persistentDataPath),真正的远程下载通常只占少量字节。这就带来了三个必须回答的问题:每次启动都要全量扫一遍 bundle 吗?—— 不能,几百上千个文件算 MD5 会拖垮冷启动。于是有了"快路径"。中途杀进程 / 断网 / 崩溃,本地会留下什么?—— 于是有了.download草稿、Asset_Temp临时目录和"catalog 即提交点"的原子提交。UI 上写"资源下载中,速度 x MB/s",但实际在做本地拷贝,算不算骗用户?—— 于是在第三周,我们把"拷贝"从"下载"里拆了出去。二、四条核心设计原则这三周的迭代,最后收敛成四条原则。后面所有细节都是这四条原则的推论。原则 1:以最终 catalog 为唯一权威不再"先下载整套 baseline 再叠加热更",而是先确定本轮的targetCatalog,再用 catalog 引用的 bundle 集合反推缺失资源。hasHotfix = bundleVersion != "-1" !string.IsNullOrEmpty(bundleUrl) hasHotfix == true → targetCatalog = hotfix catalog = {bundleUrl}/catalog_1.bin hasHotfix == false → BundleVersion = "0",targetCatalog = baseAPK catalogmanifest 负责归属,catalog 负责引用:manifest 只登记 bundle/代码热更包的归属和 md5,不管 catalog 自己的 md5;catalog 的一致性通过文件 MD5 比较来判定——快路径比的是 catalog 文件的 MD5,而不是版本号字符串。一个容易漏掉的点:代码热更包hotfix不是Addressables catalog 条目,由LoadHotfixCodeStep直接从Asset/hotfix加载。所以快路径只看 catalog 是不够的,必须同时校验本地代码包:有热更 → 对照 hotfix manifest 中hotfix的 md5无热更 → 对照 baseAPK manifest 中hotfix的 md5这一条是迭代中"踩"出来的:纯代码热更会改变 manifest 里hotfix的 md5,即使 catalog 完全没变。早期版本因此误判命中快路径,代码更新没生效。对应提交:热更资源检出与校验流程:加入热更文件校验,不会跳过检测(8-21)。原则 2:catalog 落地 = 本次更新成功(原子提交)提交顺序: 1. 移动所有 Asset_Temp/*.bundle 和 Asset_Temp/hotfix 到 Asset/ 2. 移动 manifest 3. 守卫:确认所有计划中的 bundle 在 Asset/ 都已就位,缺任何一个则中止提交 4. 提交点:catalog 最后落地(Asset_Temp/catalog_1.bin → Asset/catalog_1.bin) 5. 版本号紧随 catalog 落地写入 SaveLastBundleVersion() 6. 删除 Asset_Temp/因为 catalog 是最后落地的,catalog 之前中断 → 快路径必然 miss → 下次启动重新收敛;catalog 之后中断 → 只剩删临时目录的清理动作。整个流程天然幂等,不需要额外的"中断标记"。原则 3:信任上一次成功提交,能不算就不算快路径命中条件:Asset/catalog_1.bin == targetCatalog 且(无 hotfix,或 Asset/hotfix 的 md5 == hotfix manifest["hotfix"].md5) → SkipSyncSteps = true → ValidateCatalogStep / DownloadHotfixStep 直接 return → 不扫 bundle、不解析 catalog注意这里是逐字节比较 catalog 文件,而不是比版本号——版本号可能因为中断而没写成,字节不会骗人。原则 4:做减法,而不是加机制迭代过程中我们删掉了两个看起来很"稳"的机制:FileMd5Dictcookie 机制:原本把 MD5 结果缓存起来避免重复计算。问题是它既带来崩溃窗口风险,又无法检测文件损坏。最终改为对本地文件计算真实 md5。中断标记机制(Rebuild / Download marker):改为依赖PrepareTemporaryDirectory()清理残留 + catalog 提交点来保证一致性。少一个需要持久化的状态,就少一类"状态和现实不一致"的 bug。三、迭代时间线:关键节点与事件三周里这条链路经过 33 次提交,可以清楚看到三个阶段:架构落地 → 定版收敛 → 职责分离。日期关键提交阶段08-19 15:59热更资源检出与校验流程:架构文档① 设计08-19 17:12落地实现和第一轮重构①08-19 17:44兼容性校验①08-19 18:21保证CommitTempToAsset的原子性,可自愈、可中断①08-19 18:41打包:添加选项跳过 bundle 拷贝入 StreamingAssets①08-20 09:28快路径实现② 收敛08-20 09:57落实 bundle 文件的存在去重下载,不用持久化的方法②08-20 12:00基线 bundle 生成后生成 manifest②08-20 12:22基线 bundle 生成后压缩catalog.bin②08-20 14:31基线 bundle 生成后拷贝热更代码文件②08-20 16:43回退旧版本使用快路径,跳过后续多余步骤②08-20 17:37修复 hotfix 代码热更拷贝、catalog_1.hash拷贝②08-21 11:03加入热更文件校验,不会跳过检测② 加固08-21 14:39补全错误码②08-21 14:40hotfix 解包工具②08-21 15:20热更本地化②08-24 09:43热更过程优化:去除多余的语义文件③ 定版08-24 11:27中途断点,可以复用上次下载过的 bundle 包③08-24 12:09拷贝时候展示拷贝的提示,不显示下载③08-24 14:42热更下载:提示和日志优化③09-01 12:01cherry-pick:CommitGuard 保护打 apk 时候的基线④ 工程化09-01 12:02加入基线固定按钮④09-01 12:03cherry-pick:apk bundle 并发下载④09-09 11:35切分拷贝基线文件,这样可以更精准地展示下载速度⑤ 职责分离09-09 14:42bugfix:修复弹窗重试点击无反应⑤两个"文档定版日期"正好落在时间线上:8-19(catalog 驱动首启同步)和8-24(草稿转正 + 正式目录语义)。而9-9的方案文档,是在这次迭代的最后一天落地的。三个最值得复盘的节点节点一(8-19):把"下载 baseline 再叠热更"改成"catalog 驱动"。旧思路是"两层":先铺一整套基线,再把热更盖上去。问题是基线体积巨大且大部分和本地重复,首启体验完全不可控。新思路反过来——先确定这一轮最终要用的 catalog,再反推差集。这个反转是整条链路的根,后面所有机制都建立在它之上。节点二(8-24):区分"草稿"与"正式"。这一版明确了目录语义:Asset/file 正式文件 Asset/file.download 下载草稿(启动时统一清理) Asset_Temp/ catalog / manifest 的临时提交区bundle 和 hotfix 只认正式文件,半成品一律躺在.download里;md5 通过后才"转正"。这样"半截图文件混入正式目录"这一类问题从根上消失了。节点三(9-9):拷贝不是下载。即使流程已经稳定,UI 上依然存在一个"事实与展示不符"的问题——这在下一节展开。四、最终架构:九步流水线LauncherStartup顺序await每一步,通过共享的LauncherModel+HotfixAssetModel传递状态;步骤的gameObject.activeSelf == false则跳过。1 SplashStep 2 FetchDynamicConfigStep 拉配置,区分 profiles == null 的合法无热更 与 profile 漏配 3 ForceUpdateStep 4 CheckHotfixManifestStep 决定 hasHotfix / baseSource / targetCatalog;执行快路径 5 ValidateCatalogStep 获取必要 catalog/manifest,做归属校验,产出下载/拷贝计划 6 CopyBaselineStep 【9-9 新增】只处理 StreamingAssets 计划 → 完成后原地移除 7 DownloadHotfixStep 只跑剩余远程下载项 + catalog 刷新/提交尾巴 8 LoadHotfixCodeStep 9 InvokeEntryStep整条启动链路的决策全貌:

相关新闻

基于 STM32 的老人健康检测与跌倒监测系统

基于 STM32 的老人健康检测与跌倒监测系统

基于 STM32 的老人健康检测与跌倒监测系统设计 导语一、系统功能总览二、核心模块选型对比 2.1 主控模块选型2.2 心率血氧模块选型2.3 温度模块选型2.4 加速度模块选型2.5 蓝牙模块选型 三、系统接线总表四、系统软件设计 4.1 主程序流程4.2 跌倒检测流程4.3 心率血氧采集流程4…

2026/9/13 23:42:18 阅读更多 →
CopilotKit × Google ADK:工具渲染与推理链(Tool Rendering + Reasoning Chain)Demo 的架构原理与 QA 验证指南

CopilotKit × Google ADK:工具渲染与推理链(Tool Rendering + Reasoning Chain)Demo 的架构原理与 QA 验证指南

CopilotKit Google ADK:工具渲染与推理链(Tool Rendering Reasoning Chain)Demo 的架构原理与 QA 验证指南 【免费下载链接】CopilotKit The Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Ma…

2026/9/13 23:42:18 阅读更多 →
AI降重工具原理与使用指南:率零降AI率实战

AI降重工具原理与使用指南:率零降AI率实战

1. 项目背景与需求分析"率零降AI率使用教程"这个标题直指当前学术写作领域的一个痛点需求——如何有效降低论文中被AI检测工具识别出的"AI生成率"。随着AI写作工具的普及,学术机构普遍加强了对AI生成内容的检测力度,这使得许多合理使…

2026/9/13 23:42:18 阅读更多 →

最新新闻

视频元数据管理工具与批量处理实战指南

视频元数据管理工具与批量处理实战指南

1. 视频元数据管理的重要性与痛点在数字媒体爆炸式增长的今天,视频文件已成为我们日常工作和娱乐的重要组成部分。每个视频文件都携带了大量元数据(Metadata),这些隐藏在文件内部的信息记录了视频的标题、作者、创建日期、版权信息…

2026/9/15 2:04:12 阅读更多 →
OpenHarmony下Flutter生命周期检测:从信号错乱到稳定可用的实战指南

OpenHarmony下Flutter生命周期检测:从信号错乱到稳定可用的实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:04:12 阅读更多 →
身份可见性与智能平台:如何收缩IAM攻击面

身份可见性与智能平台:如何收缩IAM攻击面

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:04:12 阅读更多 →
微信小游戏源码调试与改造:从猫咪游戏入门到Unity打包上架

微信小游戏源码调试与改造:从猫咪游戏入门到Unity打包上架

简介:这套微信小游戏猫咪源码包,是一份面向微信小游戏开发初学者或对H5游戏感兴趣的读者的学习参考资源,主要用于了解小游戏页面搭建、猫咪形象展示与简单交互的实现方式,通过实际工程文件降低上手门槛。压缩包约49KB,…

2026/9/15 2:04:12 阅读更多 →
模式识别实验代码:Bayes、Fisher、KNN与PCA人脸识别实战

模式识别实验代码:Bayes、Fisher、KNN与PCA人脸识别实战

简介:基于Python的模式识别实验代码包,直接对应本科模式识别课程常见实验任务,适合计算机/人工智能相关专业学生对照学习与完成实验报告。代码包围绕三类典型实验展开:基于FAMALE.TXT与MALE.TXT建立Bayes性别分类器,并…

2026/9/15 2:04:12 阅读更多 →
前端面试进阶:安全取值、Promise.all手写与闭包内存泄漏实战解析

前端面试进阶:安全取值、Promise.all手写与闭包内存泄漏实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:03:12 阅读更多 →

日新闻

Java高级技术:从语言特性到性能优化全解析

Java高级技术:从语言特性到性能优化全解析

1. Java高级技术概述Java作为一门成熟的编程语言,经过二十多年的发展已经形成了完整的生态系统。在企业级应用开发、大数据处理、移动开发等领域,Java都占据着重要地位。掌握Java高级技术不仅意味着能够编写更高效的代码,更代表着开发者能够解…

2026/9/15 0:00:23 阅读更多 →
C#与Halcon结合的工业视觉处理实战指南

C#与Halcon结合的工业视觉处理实战指南

1. 项目概述:C#与Halcon强强联合的视觉处理利器这个基于C#和Halcon的视觉处理Demo项目,是我在工业质检领域摸爬滚打多年后提炼出的实战精华。它完美融合了C#的界面开发优势与Halcon强大的图像处理能力,就像给视觉工程师配上了一把瑞士军刀。项…

2026/9/15 0:00:23 阅读更多 →
32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

1. 为什么“32路复合型”不是营销话术,而是工业现场真实痛点的硬解你有没有遇到过这样的场景:在某大型能源站的PLC机柜里,十几台不同年代、不同品牌的温控仪、电表、气体分析仪、阀门控制器,全靠RS-485总线挂在一根线上&#xff0…

2026/9/15 0:00:23 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/14 5:45:49 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/15 1:32:25 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/15 1:32:21 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/14 17:35:10 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/14 16:59:29 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/14 5:45:14 阅读更多 →