1、首先 ,如果你对HybridCLR 不熟悉的话,建议先去HybridCLR官网看看,官网上文档写得很清楚,还有对Addressable不清楚的话 ,建议先去看我上几篇写得关于Addressable那部分
2、我这边也大概说一下HybridCLR,HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生c#热更新解决方案,作者改造了IL2cpp运行时代码 ,使它由纯AOT runtime变成AOT+Interpreter 混合runtime,进而原生支持动态加载assembly,从底层彻底支持了热更新相比之前的热更 方案 tolua xlua ,效率都要高,而且也不用写lua 了,对于初学者也省了学习lua 的成本,直接用C#一撸到底,具体来说HybridCLR做了以下几点工作:
(1)实现了一个高效的元数据(dll)解析库
(2) 改造了元数据管理模块,实现了元数据的动态注册
(3) 实现了一个IL指令集到自定义的寄存器指令集的compiler
(4) 实现了一个高效的寄存器解释器
(5) 额外提供大量的instinct函数,提升解释器性能
3、HybridCLR 热更流程
(1) 直接安装HybridCLR,我这边是通过Add package from git URL,首先你要安装git ,直接上图
直接执行Add 就可以了,成功之后,就能在Packages里面看到HybridCLR了,然后打开菜单HybridCLR/Installer,点击安装进行等待,安装结束后会打印安装成功日志。注意:还有一点,对于unity 版本 官方建议2019.4.40、2020.3.26+、 2021.3.0+、2022.3.0+ 中任一版本,对于Windows的平台 装VS 的时候,一定要安装Unity的游戏开发 和 使用c++的游戏开发 组件,其中C++游戏开发组件 一定要安装相关系统的sdk ,你是win10 的时候 就安装win10 最新的sdk 就行了 ,不然打包的时候 会报这种类似的错
Could not set up a toolchain for Architecture x64. Make sure you have the right build tools installed for il2cpp builds. Details,
(2) 首先把工程划分Aot模块和热更模块,可以把Assembly-CSharp 作为AOT程序集 也可以作为热更程序集,无论哪种拆分方式需要开发者设置程序集之前的依赖关系,还有一点要注意:请不要在AOT程序集中引用热更新程序集,这会导致打包出错,如果把Assembly-CSharp作为AOT程序集,更新程序集就要关闭auto reference选项
我这边也是跟官方一致,在Assets/HotUpdate 新建HotUpdate 程序集,然后HybridCLRSettings 里面填一下热更dll 的名字就好了
打包之前,先跑一遍 HybridCLR/Generate/All,注意在Assets/HybridCLRGenerate/AOTGenericReferences 脚本里面PatchedAOTAssemblyList 的dll 都是你要补充的AOT 的元数据,如果不补充的话,就打个比方,你可以在热更里面用List 和 List,但是不能用new List(),因为这是在AOT 实例化List 和 List,还有个办法,如果想用的话 ,先在AOT实例化一下new List() (不建议用这个方法),还是老老实实的补充元数据吧
建议补充元数据 直接读这个列表 ,这个肯定不会遗漏的,当然了 还有更好的办法 不用补充元数据,直接用商业版的
full generic sharing 完全泛型共享技术,相比补充元数据技术,工作流更简单,既不需要随包携带或者下载补充元数据dll,也不需要加载补充元数据dll,包体大小和内存都明显降低 具体可以看HybridCLR官网,HybridCLR/Generate/All 之后,在工程HybridCLRData/HotUpdateDlls/{对应的平台}就能看到热更dll 了
对应的元数据 dll 在HybridCLRData/AssembliesPostIl2CppStrip/{对应的平台}
然后打包测试就行了 ,我是直接测的安卓平台,在StreamingAssets 下面 有热更dll 和需要补充的元数据dll ,等下一篇结合Addressable 就直接放到资源服上,做远端下载就行了 ,然后就在官方例子下直接改的LoadDll 脚本
private void Start()
{
List<string> aotDllList = new List<string>
{
"mscorlib.dll",
"System.dll",
"System.Core.dll", // 如果使用了Linq,需要这个
// "Newtonsoft.Json.dll",
// "protobuf-net.dll",
};
StartCoroutine(LoadDLLBase(aotDllList));
}
IEnumerator LoadDLLBase(List<string> aotDllList)
{
for (int i = 0; i < aotDllList.Count; i++)
{
yield return StartCoroutine(GetFileBytes(Path.Combine(Application.streamingAssetsPath, $"{aotDllList[i]}.bytes")));
}
StartCoroutine(GetFileBytes(Path.Combine(Application.streamingAssetsPath, "HotUpdate.dll.bytes"), true));
}
IEnumerator GetFileBytes(string path, bool ishot = false)
{
var request = UnityWebRequest.Get(new System.Uri(path));
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
yield break;
}
byte[] data = request.downloadHandler.data;
if (ishot)
{
Assembly hotUpdateAss = Assembly.Load(data);
Type type = hotUpdateAss.GetType("Hello");
type.GetMethod("Run").Invoke(null, null);
}
else
HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(data, HomologousImageMode.SuperSet);
因为安卓平台下的StreamingAssets 不能用File.ReadAllBytes,用得UnityWebRequest 加载,File.ReadAllBytes 只能用于PC 和IOS ,打包 测试没问题
注意:有时候 可能会遇到热更用到某类型被裁剪了 ,要注意一下link.xml 文件 这都是要保留的类型,HybridCLR给提供了便捷的菜单命令HybridCLR/Generate/LinkXml, 能一键生成热更新工程里的所有AOT类型及函数引用。特别注意:如果你主工程中没有引用过某个程序集的任何代码,即使在link.xml中保留,该程序集也会被完全裁剪。因此对于每个要保留的AOT程序集, 请确保在主工程代码中显式引用过它的某个类或函数
总结:这一篇就是简单说一下HybridCLR 基本流程,下一篇会结合Addressable 部分来详细说明,有哪里不对的 ,欢迎小伙伴来指正哈