尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Unity热更新实战:ILRuntime环境搭建与配置全攻略
1. 项目概述为什么要在Unity里折腾ILRuntime如果你是一个Unity开发者尤其是项目涉及到热更新需求那么“ILRuntime”这个名字你大概率不会陌生。简单来说ILRuntime是一个为Unity等C#环境设计的纯C#热更新解决方案。它的核心价值在于允许你在不重新发布游戏客户端即不经过应用商店审核的情况下动态加载和执行新的C#逻辑代码。这对于需要频繁更新活动、修复线上Bug、甚至扩展核心玩法的移动端游戏来说几乎是刚需。我最初接触ILRuntime是因为手头一个上线项目遇到了一个紧急的线上逻辑错误。重新打包、提审、等待平台审核这个周期对于需要快速响应的运营活动来说是致命的。ILRuntime提供了一条“捷径”。但这条捷径的起点就是一个稳定、可靠的环境搭建。网上的资料零散且版本混杂新手很容易在配置环节就踩坑放弃。所以这份笔记不仅是我个人搭建过程的记录更希望能为你梳理出一条清晰、可复现的路径避开我当初遇到的那些“坑”。本次环境搭建的目标是在Unity编辑器中成功配置ILRuntime并运行一个最简单的热更新脚本示例验证整个热更新流程从代码编译、加载到执行的完整性。我们会基于目前相对稳定和主流的版本来进行。2. 环境搭建前的核心准备与工具选型在开始敲命令之前理清思路和准备好工具同样重要。这一步没做好后面会问题不断。2.1 明确你的Unity版本与ILRuntime版本这是最重要的一步版本不匹配是绝大多数错误的根源。ILRuntime的迭代与Unity的版本特别是.NET运行时版本紧密相关。Unity版本建议使用Unity 2019.4 LTS或更新版本如2020.3 LTS 2021.3 LTS。LTS长期支持版本稳定性最好。特别注意如果你使用的是Unity 2021.2及以上版本默认的“托管堆栈”技术Managed Stripping Level可能会剥离掉ILRuntime需要的依赖需要特殊处理。我们以Unity 2019.4 LTS为例这是目前最广泛使用的稳定版本之一。ILRuntime版本访问ILRuntime的GitHub仓库https://github.com/Ourpalm/ILRuntime查看Release。对于Unity 2019建议使用v2.0.0或更新的稳定版本。v1.x版本与v2.x版本在API上有一些不兼容的改动新项目建议直接从v2.x开始。本笔记基于ILRuntime 2.0.2进行。.NET版本在Unity Player Settings中确保“Api Compatibility Level”设置为.NET 4.x或.NET Standard 2.0。ILRuntime需要完整的.NET 4.x类库支持.NET Standard 2.0也是一个兼容性很好的选择。注意不要使用“.NET Framework”这是旧的桌面框架而是选择“.NET 4.x”或“.NET Standard 2.0”这个Unity提供的选项。2.2 获取ILRuntime的两种方式与选择你有两种主要方式将ILRuntime集成到你的Unity项目中UPM包推荐这是最简洁的方式。如果你的Unity版本支持2019.3可以直接通过Git URL添加。在Unity编辑器中打开Window - Package Manager。点击左上角的“”号选择“Add package from git URL...”。输入ILRuntime的Git仓库地址https://github.com/Ourpalm/ILRuntime.git#upm点击“Add”。Unity会自动克隆仓库并导入UPM格式的包。这种方式便于版本管理和更新。直接导入源码从GitHub Release页面下载ILRuntime_xxx.unitypackage文件。在Unity中直接双击该unitypackage文件将所有文件导入到你的项目Assets目录下通常建议放在Assets/ILRuntime文件夹内。这种方式更直接但后续更新需要手动替换文件。如何选择对于新项目和学习目的强烈推荐使用UPM方式干净且易于管理。如果你需要深度定制ILRuntime源码或者项目结构有特殊要求则可以选择导入源码。本笔记后续操作基于UPM包方式展开因为这是未来的趋势。2.3 项目结构规划在开始前想好你的代码如何组织能避免后期的混乱。我建议在Assets目录下创建如下结构Assets/ ├── ILRuntime/ (由UPM包自动创建无需手动管理) ├── HotFix/ (热更新代码工程存放需要热更的C#脚本) │ ├── HotFix.csproj (热更新工程文件) │ └── Scripts/ (热更新C#脚本) ├── Game/ (主工程代码Unity常规脚本) └── Resources/ (或其他资源目录存放编译好的热更新程序集)HotFix文件夹将作为一个独立的Visual Studio或Rider工程存在它会被编译成.dll程序集然后由主工程中的ILRuntime加载执行。3. 创建与配置热更新工程HotFix Project热更新代码不能直接放在Unity的Assets/Scripts目录下编译因为那样会被Unity直接编译进主程序集。我们需要一个独立的“输出程序集”的工程。3.1 使用Visual Studio创建类库项目打开Visual Studio2019或2022均可选择“创建新项目”。搜索并选择“类库.NET Framework”注意不是“.NET Core”或“.NET Standard”。项目名称设为HotFix位置选择你Unity项目的Assets/HotFix目录。在下一步中目标框架务必选择.NET Framework 3.5或.NET Framework 4.x。为了与Unity的.NET 4.x兼容性级别最大程度匹配选择.NET Framework 4.7.2是一个安全的选择。点击“创建”。3.2 配置项目依赖与输出创建完成后需要进行关键配置添加ILRuntime引用在解决方案资源管理器中右键HotFix项目 - “添加” - “引用”。在弹出的窗口中点击“浏览”导航到你的Unity项目目录。UPM包安装的ILRuntime DLL路径通常类似于YourProject/Library/PackageCache/com.ourpalm.ilruntime2.0.2/Artifacts/。选择ILRuntime.dll和ILRuntime.Mono.Cecil.dll如果存在添加引用。如果是源码导入方式则引用Assets/ILRuntime/ILRuntime目录下编译产生的DLL。修改输出路径右键项目 - “属性”。在“生成”选项卡中将“输出路径”修改为指向Unity项目的Assets/Resources目录或其他你计划加载程序集的目录例如..\..\Resources\。这样编译生成的HotFix.dll会直接输出到Unity可读取的Resources文件夹。可选但重要配置条件编译符号在“生成”选项卡中找到“条件编译符号”。添加UNITY_2019_4_OR_NEWER和ILRuntime。这允许你在热更新代码中编写条件编译代码例如#if ILRuntime ... #endif来处理只在ILRuntime环境下特殊的逻辑。编写一个简单的热更新脚本在HotFix项目中创建一个C#类例如HelloILRuntime.cs。using System; using ILRuntime.Runtime.Enviorment; namespace HotFix { public class HelloILRuntime { public static void SayHello() { Console.WriteLine([HotFix] Hello, ILRuntime! This is from dynamically loaded DLL.); // 在Unity中Console.WriteLine会输出到Unity的Console窗口 } public int Add(int a, int b) { return a b; } } }生成程序集在Visual Studio中选择“Release”配置调试初期也可以用Debug然后“生成解决方案”。检查你的Unity项目Assets/Resources文件夹下是否出现了HotFix.dll文件。同时请务必一同复制生成的HotFix.pdb文件如果存在它包含调试符号对于错误定位至关重要。实操心得很多人在这一步只复制了DLL忽略了PDB文件。当热更新代码报错时如果没有PDB错误堆栈只会显示模糊的偏移地址而不是具体的文件名和行号给调试带来巨大困难。务必保证DLL和PDB同时存在。4. 在Unity主工程中集成与加载ILRuntime现在我们回到Unity主工程编写加载和执行热更新代码的逻辑。4.1 创建ILRuntime加载管理器在Assets/Game/Scripts下创建一个新的C#脚本例如ILRuntimeManager.cs。这个脚本将负责ILRuntime运行时的生命周期管理。using System; using System.IO; using UnityEngine; using ILRuntime.Runtime.Enviorment; using ILRuntime.Runtime.Intepreter; using AppDomain ILRuntime.Runtime.Enviorment.AppDomain; // 避免与System.AppDomain冲突 public class ILRuntimeManager : MonoBehaviour { private AppDomain _appDomain; private MemoryStream _dllStream; private MemoryStream _pdbStream; void Start() { InitILRuntime(); LoadHotFixAssembly(); InvokeHotFixMethod(); } void InitILRuntime() { // 1. 创建AppDomain实例它是ILRuntime的执行环境 _appDomain new AppDomain(); // 2. 重要注册跨域适配器 // ILRuntime在调用热更新DLL中的方法时如果涉及值类型如Vector3或委托回调 // 需要额外的适配器来桥接主工程和热更新工程之间的类型系统。 // 首次运行可以先不注册遇到相关错误时再按需添加。 // RegisterCrossBindingAdaptor(); } void LoadHotFixAssembly() { // 3. 从Resources加载热更新程序集 TextAsset dllAsset Resources.LoadTextAsset(HotFix); // 加载HotFix.bytes TextAsset pdbAsset Resources.LoadTextAsset(HotFix.pdb); // 加载HotFix.pdb.bytes if (dllAsset null) { Debug.LogError(Failed to load HotFix.dll from Resources.); return; } _dllStream new MemoryStream(dllAsset.bytes); if (pdbAsset ! null) { _pdbStream new MemoryStream(pdbAsset.bytes); } try { // 4. 加载程序集 _appDomain.LoadAssembly(_dllStream, _pdbStream, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider()); Debug.Log(HotFix Assembly Loaded Successfully.); } catch (Exception e) { Debug.LogError($Load Assembly Failed: {e}); } } void InvokeHotFixMethod() { if (_appDomain null) return; try { // 5. 调用热更新DLL中的静态方法 _appDomain.Invoke(HotFix.HelloILRuntime, SayHello, null, null); // 6. 调用热更新DLL中的实例方法 object instance _appDomain.Instantiate(HotFix.HelloILRuntime); int result (int)_appDomain.Invoke(HotFix.HelloILRuntime, Add, instance, 10, 20); Debug.Log($Invoke HotFix Add Method, Result: {result}); } catch (Exception e) { Debug.LogError($Invoke HotFix Method Failed: {e}); } } void OnDestroy() { // 7. 清理资源 _dllStream?.Close(); _pdbStream?.Close(); _appDomain?.Dispose(); } }4.2 处理程序集文件与Unity配置转换DLL为TextAssetUnity的Resources.Load默认不能直接加载.dll文件。我们需要将HotFix.dll和HotFix.pdb重命名为.bytes扩展名Unity会将其识别为TextAsset二进制文本资源。将Assets/Resources/HotFix.dll重命名为HotFix.bytes将Assets/Resources/HotFix.pdb重命名为HotFix.pdb.bytes这样Resources.LoadTextAsset(HotFix)就能加载到DLL的数据。Unity播放器设置关键步骤打开Edit - Project Settings - Player。在“Other Settings”区域Api Compatibility Level选择.NET 4.x或.NET Standard 2.0。Scripting Backend对于独立平台PC、Mac选择Mono或IL2CPP均可。但对于iOS平台必须使用IL2CPP并且需要额外配置。对于AndroidMono和IL2CPP也都支持但IL2CPP性能和安全更好。使用IL2CPP时Managed Stripping Level如果使用IL2CPP这个设置可能会剥离ILRuntime需要的依赖。建议在开发阶段先设置为Low或Minimal上线前再根据链接报告调整。设置为Disabled最安全但包体会增大。创建测试场景在Unity中创建一个空场景创建一个GameObject将ILRuntimeManager脚本挂载上去。4.3 运行测试点击Unity播放按钮。如果一切配置正确你将在Console窗口中看到如下输出[HotFix] Hello, ILRuntime! This is from dynamically loaded DLL. Invoke HotFix Add Method, Result: 30恭喜这标志着你的ILRuntime基础环境已经搭建成功并且完成了第一次跨域代码调用。5. 进阶配置与性能优化要点基础跑通只是第一步要让ILRuntime在项目中稳健运行还需要进行一系列进阶配置。5.1 注册跨域继承适配器CLR Binding这是ILRuntime中最复杂但也最关键的部分。当热更新脚本需要继承主工程中的MonoBehaviour、使用UnityEngine.Vector3等值类型、或者主工程需要监听热更新中的事件时就需要“适配器”来告诉ILRuntime如何正确地进行交互。为什么需要因为主工程Unity和热更新工程HotFix编译后处于两个不同的“域”它们的类型系统默认是隔离的。直接传递一个主工程的Liststring到热更新工程中使用会导致类型转换错误。如何操作ILRuntime提供了生成适配器代码的工具。通常位于导入的ILRuntime包中有一个GenerateCLRBindingByAnalysis脚本。在Unity编辑器中创建一个编辑器脚本例如Assets/Editor/ILRuntimeBindingGenerator.cs。编写代码调用ILRuntime提供的分析接口扫描你的主工程程序集通常是Assembly-CSharp.dll自动生成所有必要的适配器代码。执行该编辑器脚本它会在指定目录如Assets/ILRuntime/Generated生成一系列*Adaptor.cs和CLRBinding.cs文件。将这些生成的代码文件加入到你的主工程中编译。在ILRuntimeManager.InitILRuntime()方法中调用生成的CLRBinding.Initialize(_appDomain);来注册这些绑定。注意事项自动生成并非万能。对于非常复杂的泛型类、嵌套类型或者某些特殊的委托签名可能需要手动编写适配器。这是一个迭代过程通常是在运行测试时遇到InvalidCastException或NotSupportedException错误后再根据错误信息针对性添加绑定或编写手动适配器。5.2 委托与事件注册在热更新中定义的委托类型如果需要在主工程中被回调例如热更新模块抛出一个事件通知主UI更新必须显式注册。// 在InitILRuntime中注册 _appDomain.DelegateManager.RegisterDelegateConvertorUnityEngine.Events.UnityAction((action) { return new UnityEngine.Events.UnityAction(() { ((System.Action)action)(); }); }); // 还需要注册MethodDelegate例如将热更新里的一个方法转换为Action _appDomain.DelegateManager.RegisterMethodDelegateSystem.String();不注册委托转换在尝试将热更新方法绑定到Unity的Button.onClick事件时会抛出异常。5.3 值类型绑定ValueType Binding对于频繁使用的Vector3、Quaternion、Color等Unity值类型默认通过ILRuntime访问会有性能开销因为涉及装箱/拆箱。可以通过值类型绑定来优化让它们在热更新代码中像在主工程中一样高效使用。_appDomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());你需要为每种值类型实现一个继承自ValueTypeBinder的类。ILRuntime通常已经为常见的Unity类型提供了默认实现可以在其示例代码中找到。5.4 使用CLR重定向Redirection对于某些在热更新中需要调用但行为需要被修改或拦截的系统API或Unity API可以使用CLR重定向。例如你想在热更新中重写Debug.Log的行为或者修改GameObject.Find的查找逻辑。_appDomain.RegisterCLRMethodRedirection(typeof(Debug).GetMethod(Log), MyDebugLogRedirect);这是一个高级功能通常用于框架层级的定制普通热更新开发较少使用。6. 常见问题排查与调试技巧实录即使按照步骤操作也难免会遇到问题。以下是我在搭建和开发过程中遇到的典型问题及解决方案。6.1 编译与加载阶段问题问题现象可能原因排查与解决Unity报错TypeLoadException或FileNotFoundException(ILRuntime相关)1. ILRuntime的DLL未正确导入或引用。2. 主工程与热更新工程.NET版本不匹配。1. 检查Package Manager中ILRuntime包的状态或确认源码文件夹存在。2. 确认主工程Player Settings中为.NET 4.x热更新工程目标框架为.NET Framework 4.x。加载Assembly时崩溃或报错1. DLL或PDB文件损坏。2. 热更新工程引用了主工程不存在的库。3. 使用了ILRuntime不支持的C#语法如dynamic,unsafe等。1. 重新编译热更新工程确保生成成功。2. 检查热更新工程的引用只应引用.NET基础库、UnityEngine/UnityEditor部分、ILRuntime。不要引用主工程编译的DLL。3. 避免在热更新代码中使用高级语言特性。调用热更新方法时报InvalidCastException未正确注册跨域继承适配器CLR Binding。运行绑定代码生成工具并在初始化时调用CLRBinding.Initialize(_appDomain);。检查错误信息中提到的具体类型确保其适配器已生成。调用热更新方法时报NotSupportedException1. 尝试在热更新中继承/使用了未注册适配器的复杂主工程类型。2. 使用了不支持的委托签名。1. 为该类型生成或手动编写适配器。2. 注册对应的委托转换器 (RegisterMethodDelegate)。6.2 调试技巧利用PDB文件确保PDB文件随DLL一起加载。这样当热更新代码抛出异常时堆栈信息会包含文件名和行号而不是无意义的偏移地址。这是最重要的调试手段。在热更新工程中输出日志在热更新代码中使用Console.WriteLine或Debug.Log如果引用了UnityEngine输出日志。这些日志会显示在Unity的Console窗口中。使用Visual Studio附加调试有限对于主工程Unity可以用Visual Studio正常附加调试。但对于热更新代码内部的执行逻辑目前ILRuntime的原生调试支持并不完善。更常用的方式是“日志调试法”和“单元测试法”在热更新工程内编写完备的单元测试在独立环境中验证逻辑再集成到Unity中。ILRuntime的日志回调AppDomain提供了Log事件可以捕获ILRuntime内部的一些警告和错误信息。_appDomain.Log (msg) Debug.LogWarning($[ILRuntime Log] {msg});6.3 性能优化注意事项减少跨域调用每次从热更新代码调用主工程接口如访问UnityEngine.Object或反之都有一定的性能开销。应尽量减少这种跨域调用的频率。例如避免在热更新的Update方法中每帧都通过AppDomain.Invoke调用主工程函数可以考虑将数据批量传递。使用值类型绑定对于Vector3等频繁使用的值类型务必注册值类型绑定可以消除装箱开销提升性能。缓存反射结果AppDomain.Invoke使用了反射。对于需要频繁调用的热更新方法可以使用IMethod接口进行缓存。// 在初始化时缓存 IMethod sayHelloMethod _appDomain.GetType(HotFix.HelloILRuntime).GetMethod(SayHello, 0); // 在需要调用时 _appDomain.Invoke(sayHelloMethod, null, null);警惕委托分配在热更新中创建委托尤其是每帧创建可能会产生GC Alloc影响帧率。尽量复用委托实例。7. 工程化实践与持续集成考虑当项目从Demo走向正式生产环境时环境搭建就需要融入整个工作流。自动化编译脚本编写一个编辑器脚本如BuildHotFix.cs放在Assets/Editor下。该脚本可以调用Process.Start启动msbuild或dotnet build命令编译你的HotFix.csproj工程。自动将输出的DLL和PDB复制到Assets/Resources或StreamingAssets并重命名为.bytes。可以在Unity菜单栏创建一个快捷按钮“Build HotFix”一键完成热更新代码的编译和部署。版本管理热更新程序集必须有版本号。可以在编译时通过AssemblyInfo.cs或构建脚本自动生成版本如基于Git提交哈希。主工程在加载DLL前应检查版本号决定是否需要下载和更新。资源分发生产环境中热更新DLL不会放在Resources中因为Resources打包后只读。通常将DLL.bytes放在StreamingAssets或更常见的放在服务器上。游戏启动时检查本地版本与服务器版本从网络下载新的热更新包保存到PersistentDataPath然后从该路径加载。安全考虑C# DLL很容易被反编译。对于重要的游戏逻辑需要考虑对热更新DLL进行加密或混淆。ILRuntime加载Assembly时支持传入MemoryStream你可以在下载DLL后先解密再将字节流传给LoadAssembly。搭建ILRuntime环境就像为你的Unity项目打开了一扇动态之门。初期配置的繁琐换来的是后期维护和更新的巨大灵活性。整个过程最磨人的地方往往不是步骤本身而是对两个独立工程主工程、热更新工程之间界限的理解以及对跨域交互机制适配器、绑定的掌握。我的建议是从一个像本文这样最小的可运行示例开始每成功一步就加入一点点新功能比如尝试在热更新中实例化一个MonoBehaviour或者传递一个自定义类在遇到错误和解决问题的过程中你会对ILRuntime的理解越来越深。记住耐心和细致的日志是解决ILRuntime相关问题最好的伙伴。
RELATED

相关推荐

WordPress外贸B2B独立站搭建:从0到1构建高转化询盘系统

WordPress外贸B2B独立站搭建:从0到1构建高转化询盘系统

很多外贸企业主和技术人员都有这样的困惑:为什么花了几千甚至几万做的外贸网站,上线后却几乎没有询盘?问题往往不在于技术实现,而在于从一开始就忽略了外贸独立站的本质——它不是一个简单的产品展示页,而是一个需要同…

📅 2026/8/24 23:57:07
WSL2技术解析:Windows与Linux深度整合开发指南

WSL2技术解析:Windows与Linux深度整合开发指南

1. 项目概述:当Windows遇上Linux的奇妙化学反应第一次听说"WindowsLinux"这个名词时,我的程序员直觉就告诉我:这绝对不是简单的虚拟机或者双系统。经过实际测试后发现,这确实是一个令人眼前一亮的解决方案——它让Windo…

📅 2026/9/10 8:57:50
Nota常见问题解答:新手入门必知的15个关键问题

Nota常见问题解答:新手入门必知的15个关键问题

Nota常见问题解答:新手入门必知的15个关键问题 【免费下载链接】nota A document language for the browser 项目地址: https://gitcode.com/gh_mirrors/no/nota Nota作为一款面向浏览器的文档语言,为用户提供了全新的文档创作体验。本文整理了新…

📅 2026/9/9 19:03:53
MORE NEWS

更多资讯

📰

棋盘格相机标定实战:从内参矩阵到畸变校正的关键细节

简介:相机内参标定是计算机视觉的基础环节,直接影响图像畸变校正与三维测量精度。这份练习包面向需要快速上手单目相机标定的学生、研究者或开发者,定位明确:通过棋盘格图像与Python脚本,解决相机焦距、主点坐标及畸变…

📰

双端回归从「一台台串行」压到「三台并行」:Midscene.js 多设备协同测试实战

双端回归从「一台台串行」压到「三台并行」:Midscene.js 多设备协同测试实战 【免费下载链接】midscene GUI Agent for E2E Testing 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene 同一套下单用例要在 Android 和 iOS 上各跑一遍,…

📰

MCP协议与AI记忆系统融合架构解析

1. MCP协议与AI记忆系统融合的技术背景 在构建现代AI智能体时,我们面临着三个核心挑战:如何让AI连接外部世界、如何管理复杂任务流程、如何实现长期个性化。MCP(Model Context Protocol)协议与AI记忆系统的融合,正是为解决这些问题而生的技术…

📰

SEO与传统营销的核心差异与实战价值

1. 营销模式的核心差异解析SEO网络营销与传统营销最本质的区别在于流量获取路径的不同。传统营销依赖线下渠道和付费广告,比如在报纸上刊登广告、电视黄金时段插播宣传片,或者在人流密集处设置实体广告牌。这种方式的特点是投入产出比难以精确量化&#…

📰

如何用 @tiptap/static-renderer 在不创建 Editor 实例的情况下渲染 Tiptap JSON 内容?

如何用 tiptap/static-renderer 在不创建 Editor 实例的情况下渲染 Tiptap JSON 内容? 【免费下载链接】tiptap The headless rich text editor framework for web artisans. 项目地址: https://gitcode.com/GitHub_Trending/ti/tiptap 当你手里已经有一份 T…

📰

JavaWeb电商系统搭建:JSP+Servlet+MySQL实战指南

简介:本资源是一套高质量JavaWeb课程设计级实战项目——仿小米在线商城系统源码及配套数据库,面向高校计算机专业学生与Java初学者,用于完成大作业、课程设计或Web开发入门实践。项目已通过严格调试,评审得分95分以上,…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬