@[TOC](Unity + HybridCLR,近乎完美的新热更方案,从零开始(一)——Hello World)
前言
最近又新接触了一种unity热更的解决方案——HybridCLR,自称是:特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生c#热更方案。 接下来我们就来一起学习下。 下面是官方文档的链接,一切以官方为主:HybridCLR
一、HybridCLR是什么?
HybridCLR扩充了il2cpp的代码,使它由纯AOT runtime变成AOT+Interpreter 混合runtime,进而原生支持动态加载assembly,使得基于il2cpp backend打包的游戏不仅能在Android平台,也能在IOS、Consoles等限制了JIT的平台上高效地以AOT+interpreter混合模式执行,从底层彻底支持了热更新。
HybridCLR不仅支持传统的全解释执行模式,还开创性地实现了 Differential Hybrid Execution(DHE) 差分混合执行技术。即可以对AOT dll任意增删改,会智能地让变化或者新增的类和函数以interpreter模式运行,但未改动的类和函数以AOT方式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平。
我自己理解的就是:一种基于C#的热更技术,完美支持C#原生,不需要写额外的适配器啥的,直接就能用,就是把il2cpp改了下。
二、使用步骤
环境配置
unity安装的时候一定要安装IL2cpp部分,Windows Build Support(IL2CPP)或Mac Build Support(IL2CPP)。 现在支持的unity 版本:2019.4.40、2020.3.26+、2021.3.0+
我用的unity 版本是2021.3.23
Windows Win下需要安装visual studio 2019或更高版本。安装时至少要包含 使用Unity的游戏开发 和 使用c++的游戏开发 组件。 安装git Mac 要求MacOS版本 >= 12,xcode版本 >= 13,例如xcode 13.4.1, macos 12.4。 安装 git 安装cmake
创建项目
创建ConsoleToScreen脚本,方便在屏幕上看日志。
using System;
using System.Collections;
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) });
}
}
把这个脚本挂载到空场景的空物体上,在Build Settings中添加这个场景到打包场景列表
创建 HotUpdate 热更新模块
创建 Assets/HotUpdate 目录 在目录下 右键 Create/Assembly Definition,创建一个名为HotUpdate的程序集模块
安装和配置HybridCLR
Windows——>Package Manager,打开包管理器,
安装包成功后,打开HybridCLR——>Installer
配置HybridCLR
PlayerSettings的配置
创建热更脚本
Assets/HotUpdate/Hello.cs这个脚本内容是需要热更的,代码如下:
using System.Collections;
using UnityEngine;
public class Hello
{
public static void Run()
{
Debug.Log("Hello, HybridCLR");
}
}
加载热更新程序集
创建Assets/LoadDll.cs脚本,然后在main场景中创建一个GameObject对象,挂载LoadDll脚本。
using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
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
Type type = hotUpdateAss.GetType("Hello");
type.GetMethod("Run").Invoke(null, null);
}
}
运行菜单 HybridCLR/Generate/All 进行必要的生成操作这是用来生成要热更的脚本的dll文件的将{proj}/HybridCLRData/HotUpdateDlls/StandaloneWindows64(MacOS下为StandaloneMacXxx)目录下的HotUpdate.dll复制到Assets/StreamingAssets/HotUpdate.dll.bytes,注意,要加.bytes后缀!!
然后就可以打包了,运行之后的结果是这样的
测试热更新
修改Assets/HotUpdate/Hello.cs的Run函数中Debug.Log("Hello, HybridCLR");代码,改成Debug.Log("Hello, World");。运行菜单命令HybridCLR/CompileDll/ActiveBulidTarget重新编译热更新代码。将{proj}/HybridCLRData/HotUpdateDlls/StandaloneWindows64(MacOS下为StandaloneMacXxx)目录下的HotUpdate.dll复制为刚才的打包输出目录的 XXX_Data/StreamingAssets/HotUpdate.dll.bytes。
重新运行程序 结果如下
热更成功!