unity-doc-ILRuntime

概念

为什么使用ILRuntime

  • 手游为什么需要热更

手游是快节奏的应用,功能和资源更新频繁,特别是重度手游安装包大多数都是1G以上,如果不热更新,哪怕改动一行代码也要重新打包上传到网上让玩家下载。

对于IOS版本的手游包IPA,要上传到苹果商店进行审核,周期漫长,这对于BUG修复类操作是一个灾难。

使用热更,可以快速的修复bug、方便版本迭代、灵活性高;但同时也会导致代码执行速度相对变慢以及开发过程的加长。

  • C#为什么不能热更新

事实上C#是可以通过反射机制实现动态代码加载从而实现热更新;

IOS禁止热更:苹果AppStore的审核规则中,命令禁止应用程序分配具有可执行权限的内存,带有JIT功能的脚步虚拟机是无法运行,无法动态加载链接库,Android是可以的。

Android允许热更:Android平台可以直接使用原生方式进行热更,如果不需要ios热更,可以通过改mono源码读取其他dll更新,也可通过反射热更。

  • ILRuntime原理

ILRuntime借助Mono.Cecil库来读取DLL的PE信息,以及当中类型的所有信息,最终得到方法的IL汇编码,然后通过内置的IL解译执行虚拟机来执行DLL中的代码

流程

环境

  1. unity 2020.1.0a25.3171
  2. ILRuntime 1.6.5

准备

导入ILRuntime

可以通过git下载或unity的Package Manager导入

unity设置

  1. PlayerSettings 中勾选 Allow unsafe mode
  2. ProjectSettingsPlayerScriptingDefineSymbols添加 ILRuntimeDISABLE_ILRUNTIME_DEBUG
  3. Assets 目录里建立一个名为 smcs.rsp 的文本文件,并且写入内容 -unsafe

使用

  1. 在项目里面创建程序集 Create->Assembly Definition
    • 这里是IL
  2. 在项目的 Library\ScriptAssemblies 目录找到对应的程序集
    • IL.dll
    • IL.pdb
  3. 在 Asset 目录创建一个目录 HotFix,把 IL.dll 和 IL.pdb 复制进去

委托

  • 没跨域,可以正常直接使用ActionFunc
  • 如果跨域,带参数Action,通过appdomain.DelegateManager.RegisterMethodDelegate<参数类型>()注册适配器
  • 如果跨域,带参数Func,通过appdomain.DelegateManager.RegisterFunctionDelegate<参数类型,返回值>()注册适配器
  • 使用非系统级ActionFunc外的委托,需要进行委托转换处理DelegateConvertor

继承

  • 没跨域,按正常使用继承
  • 如果跨域,需要写适配器 CrossBindingAdaptor 并注册RegisterCrossBindingAdaptor
  • 跨域继承的子类中,无法调用当前重载以为的虚函数
  • 跨域继承中,不能在基类的构造函数中调用该类的虚函数

反射

  • 默认情况下,System.Reflection命名空间中的方法,并不可能得知ILRuntime中定义的类型,因此无法通过Type.GetType等接口取得热更DLL里面的类型。而且ILRuntime里的类型也并不是一个System.Type
  • ILRuntime可用反射辅助类ILRuntimeType ILRuntimeMethodInfo ILRuntimeFieldInfo
  • 在Unity主工程中不能通过new T()的方式来创建热更工程中的类型实例

CLR重定向

  1. 获取需要重定向的方法
  2. 编写重定向到新的方法
  3. 使用 appdomain.RegisterCLRMethodRedirection 注册重定向方法

CLR绑定

热更dll调用非热更代码时,减少gc使用。

  1. 添加导出脚本
  2. 编辑生成脚本
  3. InitializeILRuntime 使用 ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain); 初始化

调试

  1. 下载vs插件https://github.com/Ourpalm/ILRuntime/releases/tag/v2.0.2选择下载ILRuntimeDebuggerLauncher.vsix,仅支持window

  2. 初始化ilruntime的时候加上代码

    1
    appdomain.DebugService.StartDebugService(56000);
  3. vs打开调试,选择Attach to ILRuntime

注意

  • 不能继承mono
  • 要有命名空间
  • 不要在非热更代码代码使用热更代码的类实例,需要用非热更代码里面的抽象类或接口类进行替换。
  • 注册委托只能写在主工程里,不能写在热更工程里。
  • ILRuntime的Type ILRuntimeWrapperType 与System里面的Type不是一个类型,所以不能传热更工厂的Type到主工厂进行反射使用
  • 非线程安全,不可多个线程执行同一段代码
  • 反射能不使用最好不使用,在主代码和热更代码执行反射获得的结果是不一样的,反射代码最好都在热更代码实现(例如动态设置字段值),除非热更代码里面没使用到

使用示例2

环境

  • unity 2021.3.1f1c1

  • mac

准备

  • unity package manager 导入 ILRuntime 2.0.2

  • 在 ProjectSettings 的 Player 中勾选 Allow unsafe mode

  • 在 ProjectSettings 的 Player 的 ScriptingDefineSymbols添加 ILRuntimeDISABLE_ILRUNTIME_DEBUG

  • 在 Assets 目录里建立一个名为 smcs.rsp 的文本文件,并且写入内容 -unsafe

相关地址

ILRuntime-git
ILRuntime-home
ILRuntime学习项目代码
Unity资源热更及代码热更框架
ILRuntime来实现热更新的优与劣
protobuf3简化