HybridCLR(原 Huatuo)是 Unity 平台革命性的热更新解决方案,它通过扩展 Unity 的 IL2CPP 运行时,实现了基于原生 C# 的完整热更新能力。下面从原理到实践全面解析这一技术。
原始 IL2CPP 流程:
C#代码 → IL → AOT编译 → Native代码
HybridCLR 增强流程:
C#热更代码 → IL → 解释执行/JIT编译
↘ 补充元数据 → AOT运行时
AOT(Ahead-of-Time)补充元数据:为 IL2CPP 提供缺失的反射信息
IL解释器:实时解释执行热更代码的 IL 指令
元数据注册:动态注册新类型到运行时系统
桥接机制:无缝连接 AOT 和 Interpreter 代码
# 通过UPM安装(Unity 2019+)
1. 添加Package Manager源:
https://github.com/focus-creative-games/hybridclr_unity.git
# 或手动安装
1. 下载HybridCLR Unity包
2. 解压到项目Assets目录
3. 导入HybridCLR菜单
// 初始化脚本示例
using HybridCLR.Editor;
public class HybridCLRInitializer
{
[MenuItem("HybridCLR/Install")]
public static void Install()
{
Installer.InstallDefaultHybridCLR();
// 生成AOT泛型引用
AOTGenericReferences.Generate();
// 配置热更程序集
SettingsUtil.HotUpdateAssemblyNames = new List
{
"HotFix",
"GameLogic"
};
}
}
// 编译热更DLL(需独立VS项目)
// 项目需引用:
// - HybridCLR.Runtime
// - 主工程的AOT程序集
// 打包配置示例:
[MenuItem("HybridCLR/BuildHotfix")]
public static void BuildHotfix()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
string outputDir = $"{Application.dataPath}/../Hotfix/{target}";
CompileDllCommand.CompileDll(target, outputDir);
// 生成补充元数据
AOTMetadataGenerator.GenerateForAssembly(
$"{outputDir}/HotFix.dll",
$"{outputDir}/HotFix_AOTDll.dll"
);
}
// 将热更DLL打包为AssetBundle
[MenuItem("HybridCLR/BuildAssetBundles")]
public static void BuildAssetBundles()
{
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
string hotfixDir = $"{Application.dataPath}/../Hotfix/{target}";
// 创建临时打包目录
string tempDir = "Assets/HotfixTemp";
Directory.CreateDirectory(tempDir);
// 复制DLL到Assets目录
File.Copy($"{hotfixDir}/HotFix.dll", $"{tempDir}/HotFix.dll.bytes", true);
File.Copy($"{hotfixDir}/HotFix_AOTDll.dll", $"{tempDir}/HotFix_AOTDll.dll.bytes", true);
// 构建AssetBundle
BuildPipeline.BuildAssetBundles(
"Assets/StreamingAssets",
BuildAssetBundleOptions.ChunkBasedCompression,
target
);
Directory.Delete(tempDir, true);
}
using HybridCLR.Runtime;
public class HotfixLoader : MonoBehaviour
{
void Start()
{
StartCoroutine(LoadHotfix());
}
IEnumerator LoadHotfix()
{
// 1. 加载补充元数据
string aotDllPath = $"{Application.streamingAssetsPath}/hotfix_aotdll";
var aotReq = AssetBundle.LoadFromFileAsync(aotDllPath);
yield return aotReq;
TextAsset aotDll = aotReq.assetBundle.LoadAsset("HotFix_AOTDll.dll");
RuntimeApi.LoadMetadataForAOTAssembly(aotDll.bytes);
// 2. 加载热更程序集
string hotfixPath = $"{Application.streamingAssetsPath}/hotfix";
var hotfixReq = AssetBundle.LoadFromFileAsync(hotfixPath);
yield return hotfixReq;
TextAsset hotfixDll = hotfixReq.assetBundle.LoadAsset("HotFix.dll");
Assembly hotfixAssembly = Assembly.Load(hotfixDll.bytes);
// 3. 启动热更代码
Type entryType = hotfixAssembly.GetType("HotFix.GameEntry");
MethodInfo startMethod = entryType.GetMethod("Start");
startMethod.Invoke(null, null);
}
}
// HotFix.dll 中的代码
using UnityEngine;
public class GameEntry
{
public static void Start()
{
Debug.Log("热更代码启动!");
// 实例化热更MonoBehaviour
GameObject go = new GameObject("HotfixObject");
go.AddComponent();
}
}
public class HotfixBehaviour : MonoBehaviour
{
void Update()
{
// 完全热更的逻辑代码
transform.Rotate(0, 30 * Time.deltaTime, 0);
}
}
// 主工程需预生成泛型实例
[AOTGenericReferences]
public static class AOTGenericTypes
{
// 热更中可能用到的泛型类型
public static readonly List Types = new List
{
typeof(List),
typeof(Dictionary),
typeof(Action),
};
}
// 热更代码中可自由使用预生成的泛型
public class GenericExample
{
public void Test()
{
var list = new List(); // 已支持
var dict = new Dictionary(); // 需要补充注册
}
}
// 主工程接口定义
public interface IHotfixService
{
void ProcessData(string json);
}
// 热更工程实现
public class HotfixServiceImpl : IHotfixService
{
public void ProcessData(string json)
{
// 完全热更的实现
Debug.Log($"处理数据: {json}");
}
}
// 主工程调用
var service = new HotfixServiceImpl();
service.ProcessData("{...}"); // 无反射开销的调用
// 启动时配置解释器参数
RuntimeApi.SetRuntimeOption(
RuntimeOptionId.EnableJIT,
Application.platform == RuntimePlatform.WindowsPlayer ? 1 : 0
);
// 方法调用次数阈值(超过后触发JIT编译)
RuntimeApi.SetRuntimeOption(
RuntimeOptionId.MethodCallThreshold,
100
);
// 1. 及时卸载热更Assembly
Resources.UnloadAsset(hotfixDll);
aotReq.assetBundle.Unload(true);
// 2. 使用对象池管理热更对象
public class HotfixObjectPool
{
private static Dictionary> _pool = new();
public static T Get() where T : new()
{
var type = typeof(T);
if (_pool.TryGetValue(type, out var queue) && queue.Count > 0)
{
return (T)queue.Dequeue();
}
return new T();
}
public static void Release(object obj)
{
var type = obj.GetType();
if (!_pool.ContainsKey(type))
{
_pool[type] = new Queue
// 需要额外处理的位置:
1. 元数据加载方式:
- 使用mmap加载补充元数据
- 避免动态代码生成
2. 签名验证:
- 确保热更文件经过合法签名
- 实现完整性校验
// iOS初始化示例
#if UNITY_IOS
[DllImport("__Internal")]
private static extern void InitHybridCLRiOS(IntPtr assembly, int size);
void LoadForIOS(byte[] assemblyData)
{
IntPtr ptr = Marshal.AllocHGlobal(assemblyData.Length);
Marshal.Copy(assemblyData, 0, ptr, assemblyData.Length);
InitHybridCLRiOS(ptr, assemblyData.Length);
Marshal.FreeHGlobal(ptr);
}
#endif
// 1. 使用Memory Mapping加载
var assembly = RuntimeApi.LoadMetadataForAOTAssemblyFromMemory(
aotDllBytes,
HomologousImageMode.SuperSet
);
// 2. 多线程优化
RuntimeApi.SetRuntimeOption(
RuntimeOptionId.ThreadStackSize,
1024 * 1024 * 2 // 2MB栈空间
);
主工程(AOT部分) ├─ 引擎接口层 ├─ 核心框架 ├─ 原生插件 └─ 公共数据结构 热更工程(可更新部分) ├─ 业务逻辑 ├─ UI系统 ├─ 配置表 └─ 玩法内容 共享程序集 ├─ 接口定义 ├─ 通信协议 └─ 工具类库
版本控制:使用语义化版本管理热更程序集
差异更新:基于bsdiff实现二进制差异补丁
回滚机制:保留上一可用版本
安全验证:DLL签名+哈希校验
HybridCLR 通过创新的技术方案,实现了真正意义上的原生C#热更新,相比传统Lua方案具有显著的开发效率优势。合理运用其特性,可以构建出高性能、易维护的热更新架构,特别适合中大型商业项目。随着技术的持续演进,HybridCLR正在成为Unity热更新领域的事实标准解决方案。