跳转至

热更新

先分清三类更新

很多问题出在“热更新”这个词太笼统。实际项目里至少要分开看:

类型 更新内容 常见方案
代码 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 主工程
  → 生成热更程序集和补充元数据
  → 生成带版本、哈希、依赖的清单
  → 客户端下载到临时目录
  → 校验签名和文件哈希
  → 加载元数据
  → 加载热更程序集
  → 执行入口并检查版本
  → 失败则回退内置版本

每一步都要有日志。尤其是“下载成功但加载失败”和“加载成功但初始化失败”,这两种情况的原因完全不同。

相关文档