热更新¶
先分清三类更新¶
很多问题出在“热更新”这个词太笼统。实际项目里至少要分开看:
| 类型 | 更新内容 | 常见方案 |
|---|---|---|
| 代码 | C#、Lua 或脚本逻辑 | xLua、ILRuntime、HybridCLR |
| 资源 | 贴图、预制体、音频、关卡 | AssetBundle、Addressables |
| 配置 | 数值表、活动配置、文本 | JSON、CSV、二进制表 |
三者的回退方式不一样。代码回退要保留旧程序集,资源回退要保留旧 Bundle 和 Catalog,配置回退要能切回旧版本并清理缓存。把这三类混成一个“热更新包”,线上排查会很麻烦。
运行时的下载、切换和回退见热更新版本、下载与回退,发布物验签见热更新包与资源验签。
为什么不能直接换 C# DLL¶
Unity 在 iOS、主机等平台通常使用 IL2CPP,把 C# IL 提前编译成 C++ 和机器码。1 发布后的原生代码不能像脚本一样替换,平台也不允许随意申请可执行内存。
普通 IL2CPP 包里调用 Assembly.Load(byte[]),并不会凭空获得 JIT 能力。要动态执行新的 C# 程序集,通常需要在运行时里带一个解释器,或者扩展 IL2CPP 的元数据和执行路径。
这就是热更新方案存在的原因。
常见方案¶
xLua¶
用 Lua 写业务逻辑,C# 负责引擎和稳定框架。xLua 也支持用 Lua 替换部分 C# 方法,适合老项目做少量热补丁。2
优点是 Lua 生态成熟、更新边界清楚;代价是多一门语言,C# 和 Lua 之间频繁调用需要关注绑定和 GC。具体做法可以看 xLua。
ILRuntime¶
用纯 C# 实现一个 IL 解释器,热更程序集在独立的运行时域里执行,通过 CLR 绑定访问 Unity 和主工程代码。3
优点是业务代码仍然用 C# 写;代价是跨域调用、泛型、委托和适配器需要额外处理,热点路径要单独测。具体做法可以看 ILRuntime。
HybridCLR¶
HybridCLR 把 IL2CPP 运行时扩展成 AOT + Interpreter 的混合模式,可以动态加载 C# 程序集,并通过补充元数据支持 AOT 泛型和类型。4
它适合希望统一使用 C#、又需要覆盖 iOS 等平台的团队。需要重点处理程序集切分、代码裁剪、泛型元数据和真机验证。具体做法可以看 HybridCLR。
早期的 toLua、sLua 等方案也能在资料里看到。新项目选型时,优先看当前维护状态、目标平台和团队已有的技术栈,不要只看一份性能对比表。
一条上线流程¶
稳定 AOT 主工程
→ 生成热更程序集和补充元数据
→ 生成带版本、哈希、依赖的清单
→ 客户端下载到临时目录
→ 校验签名和文件哈希
→ 加载元数据
→ 加载热更程序集
→ 执行入口并检查版本
→ 失败则回退内置版本
每一步都要有日志。尤其是“下载成功但加载失败”和“加载成功但初始化失败”,这两种情况的原因完全不同。
相关文档¶
- 各方案的取舍:HybridCLR。
- Lua 接入:xLua。
- 纯 C# 解释器:ILRuntime。
- 上线常见问题:热更新常见问题与排查。
- 下载和回退:热更新版本、下载与回退。
- 发布物验签:热更新包与资源验签。
- 资源和 Catalog:Addressables 远程资源更新。