【unity游戏开发——热更新】HybridCLR代码热更新的使用
Unity HybridCLR热更新解决方案实践指南 本文介绍了Unity跨平台开发中热更新解决方案HybridCLR的完整实践流程。HybridCLR通过将AOT运行时与解释器混合,实现原生C#代码热更新,支持几乎所有C#特性,包括泛型、反射和多线程。 主要内容包括: HybridCLR特性:近乎完整的ECMA-335规范实现,零学习成本,支持Unity完整工作流,高性能执行和低内存占用 安装配
注意
:考虑到热更新的内容比较多,我将热更新的内容分开,并全部整合放在【unity游戏开发——热更新】专栏里,感兴趣的小伙伴可以前往逐一查看学习。
前言
1、前置知识
无论是选择 Mono 还是 IL2CPP,都是为了让你的游戏可以在尽可能多的不同设备上顺利运行。随着 Unity 不断改进其构建流程和技术栈,IL2CPP 已经成为推荐的打包方式,因为它提供了更好的性能和更广泛的平台支持。对于新项目,建议使用IL2CPP打包方式,因为它比Mono打包更高效,生成的包也会更小。
具体可以参考: 【unity进阶篇】unity如何实现跨平台及unity最优最小包体打包方式(.NET、Mono和IL2CPP知识介绍)
2、什么是HybridCLR?
HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生c#热更新解决方案。
HybridCLR扩充了il2cpp运行时代码,使它由纯AOT runtime变成AOT+Interpreter 混合runtime,进而原生支持动态加载assembly,从底层彻底支持了热更新。使用HybridCLR技术的游戏不仅能在Android平台,也能在IOS、Consoles、WebGL等所有il2cpp支持的平台上高效运行。
由于HybridCLR对ECMA-335规范 的良好支持以及对Unity开发工作流的高度兼容,Unity项目在接入HybridCLR后,可以几乎无缝地获得C#代码热更新的能力,开发者不需要改变日常开发习惯和要求。HybridCLR首次实现了将Unity平台的全平台代码热更新方案的工程难度降到几乎为零的水平。
官方文档:https://hybridclr.doc.code-philosophy.com/docs/beginner/quickstart、
3、特性
- 近乎完整实现了ECMA-335规范,只有极少量的不支持的特性。
- 零学习和使用成本。对绝大多数开发者来说写代码近乎没有限制。 热更新代码与AOT代码无缝工作,可以随意写继承、泛型、反射之类的代码。不需要额外写任何特殊代码、没有代码生成
- 完全支持多线程,包含但不限于 volatile、ThreadStatic、async Task等相关功能和特性。这是其他所有热更新方案都不支持的
- 几乎完全兼容Unity的工作流。包括且不限于支持热更新MonoBehaviour、ScriptableObject、DOTS技术,资源上挂载的热更新脚本可以正确实例化,这是其他所有热更新方案都不支持的
- 执行高效。实现了一个极其高效的寄存器解释器,所有指标都大幅优于其他热更新方案。性能测试报告
- 内存高效。 热更新脚本中定义的类跟普通c#类占用一样的内存空间,远优于其他热更新方案。内存占用报告
- 支持MonoPInvokeCallback,可以与native代码或者其他语言如lua、javascript、python良好交互
- 支持一些il2cpp不支持的特性,如makeref、 reftype、__refvalue指令
- 支持独创的 Differential Hybrid Execution(DHE) 差分混合执行技术,即可以对AOT dll任意增删改,会智能地让未改动的函数以AOT方式运行,变化或者新增的函数以interpreter模式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平
- 支持 热重载 技术,可以100%卸载程序集
支持现代的dll加密技术,有效保障代码安全
4、核心目标与解决的问题
-
突破 IL2CPP 的限制: Unity 的 IL2CPP 后端将 C# IL 代码转换为 C++ 代码再编译成原生机器码,极大地提升了运行效率和安全性,但也完全封死了传统的基于动态加载 DLL 的 C# 热更新途径。
-
提供原生 C# 体验: 相比于流行的 Lua、ILRuntime、huatuo (xLua 的 IL 模式) 等热更方案,HybridCLR 的终极目标是让开发者能够完全使用标准 C# 编写热更逻辑,无需学习额外的脚本语言(如 Lua)或忍受受限的 C# 子集(存在语法、特性、性能限制)。
-
追求高性能: 提供接近原生 AOT 代码的执行效率,显著优于解释型方案(如纯 Lua 或部分 IL 解释器)。
-
近乎完整支持: 力求支持绝大多数 C# 特性,包括泛型、反射、多线程 (async/await)、值类型操作等,让热更代码和主工程代码在能力上几乎无差别。
一、安装HybridCLR
1、安装IL2CPP
根据操作系统,安装过程中选择模块时,必须选中 Windows Build Support(IL2CPP)
或Mac Build Support(IL2CPP)
。
2、安装 com.code-philosophy.hybridclr 包
主菜单中点击Windows/Package Manager打开包管理器。如下图所示点击Add package from git URL…
填入https://gitee.com/focus-creative-games/hybridclr_unity.git
或https://github.com/focus-creative-games/hybridclr_unity.git
。
3、初始化 com.code-philosophy.hybridclr
打开菜单HybridCLR/Installer…, 点击安装按钮进行安装。 耐心等待30s左右,安装完成后会在最后打印 安装成功日志。
二、HybridCLR代码热更新实战
1、初始化Unity热更新项目
1.1 创建ConsoleToScreen.cs脚本
这个脚本对于演示热更新没有直接作用。它可以打印日志到屏幕上,方便定位错误。
创建 Assets/ConsoleToScreen.cs 脚本类,代码如下:
using System;
using System.Collections.Generic;
using UnityEngine;
public class ConsoleToScreen : MonoBehaviour
{
const int maxLines = 50;
const int maxLineLength = 120;
private string _logStr = "";
private readonly List<string> _lines = new List<string>();
public int fontSize = 15;
void OnEnable() { Application.logMessageReceived += Log; }
void OnDisable() { Application.logMessageReceived -= Log; }
public void Log(string logString, string stackTrace, LogType type)
{
foreach (var line in logString.Split('\n'))
{
if (line.Length <= maxLineLength)
{
_lines.Add(line);
continue;
}
var lineCount = line.Length / maxLineLength + 1;
for (int i = 0; i < lineCount; i++)
{
if ((i + 1) * maxLineLength <= line.Length)
{
_lines.Add(line.Substring(i * maxLineLength, maxLineLength));
}
else
{
_lines.Add(line.Substring(i * maxLineLength, line.Length - i * maxLineLength));
}
}
}
if (_lines.Count > maxLines)
{
_lines.RemoveRange(0, _lines.Count - maxLines);
}
_logStr = string.Join("\n", _lines);
}
void OnGUI()
{
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity,
new Vector3(Screen.width / 1200.0f, Screen.height / 800.0f, 1.0f));
GUI.Label(new Rect(10, 10, 800, 370), _logStr, new GUIStyle() { fontSize = Math.Max(10, fontSize) });
}
}
1.2 创建主场景
- 创建默认初始场景 main.scene
- 场景中创建一个空GameObject,将ConsoleToScreen挂到上面
- 在Build Settings中添加main场景到打包场景列表
1.3 创建 HotUpdate 热更新模块
- 创建
Assets/HotUpdate
目录 - 在目录下 右键
Create/Scripting/Assembly Definition(程序集定义)
,创建一个名为HotUpdate的程序集模块
2、配置HybridCLR
打开菜单 HybridCLR/Settings, 在Hot Update Assemblies配置项中添加HotUpdate程序集,如下图:
3、配置PlayerSettings
- 如果你用的hybridclr包低于v4.0.0版本,需要关闭增量式GC(Use Incremental GC) 选项(我这里我最新的8.1版本,所以不用关)
- Scripting Backend 切换为 IL2CPP
- Api Compatability Level 切换为 .Net 4.x(Unity 2019-2020) 或 .Net Framework(Unity 2021+)
4、创建热更新脚本
创建 Assets/HotUpdate/Hello.cs
文件,代码内容如下
using UnityEngine;
public class Hello
{
public static void Run()
{
Debug.Log("Hello, HybridCLR");
}
}
你可能会关心热更新部分的代码会不会像其他方案那样对C#语法有限制。HybridCLR是近乎完备的实现,对热更新代码几乎没有限制。极少数的例外可以查看不支持的特性。
5、加载热更新程序集
为了简化演示,我们不通过http服务器下载HotUpdate.dll,而是直接将HotUpdate.dll放到StreamingAssets目录下。
HybridCLR是原生运行时实现,因此调用Assembly Assembly.Load(byte[])即可加载热更新程序集。
创建Assets/LoadDll.cs脚本,然后在main场景中创建一个GameObject对象,挂载LoadDll脚本。
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
public class LoadDll : MonoBehaviour
{
void Start()
{
// Editor环境下,HotUpdate.dll.bytes已经被自动加载,不需要加载,重复加载反而会出问题。
#if !UNITY_EDITOR
Assembly hotUpdateAss = Assembly.Load(File.ReadAllBytes($"{Application.streamingAssetsPath}/HotUpdate.dll.bytes"));
#else
// Editor下无需加载,直接查找获得HotUpdate程序集
Assembly hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "HotUpdate");
#endif
}
}
6、调用热更新代码
显然,主工程不能直接引用热更新代码。有多种方式可以从主工程调用热更新程序集中的代码,这里通过反射来调用热更新代码。
在LoadDll.Start函数后面添加反射调用代码,如下:
void Start()
{
//...
//得到Hello类调用函数
Type type = hotUpdateAss.GetType("Hello");
type.GetMethod("Run").Invoke(null, null);
}
7、Editor中试运行
运行main场景,屏幕上会显示 ‘Hello,HybridCLR’,表示代码工作正常。
8、打包运行
-
运行菜单 HybridCLR/Generate/All 进行必要的生成操作。这一步不可遗漏!!!
-
将{proj}/HybridCLRData/HotUpdateDlls/StandaloneWindows64(MacOS下为StandaloneMacXxx)目录下的HotUpdate.dll复制到Assets/StreamingAssets/HotUpdate.dll.bytes,注意,要加.bytes后缀!!!
-
打开Build Settings对话框,点击Build And Run,打包并且运行热更新示例工程。
打包时如果出现下面的报错
IL2CPP C++代码生成器无法生成C++代码。为了构建Windows桌面的C++代码,您必须安装以下软件:带有C++编译器和Windows SDK的Visual Studio
2022或更高版本(版本10.0.19041.0或更高版本)
安装完重新打包运行,如果打包成功,并且屏幕上显示 ‘Hello,HybridCLR’,表示热更新代码被顺利执行!
专栏推荐
完结
好了,我是向宇
,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
更多推荐
所有评论(0)