概念
为什么使用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中的代码
流程
环境
- unity 2020.1.0a25.3171
- ILRuntime 1.6.5
准备
导入ILRuntime
可以通过git下载或unity的Package Manager导入
unity设置
- 在
PlayerSettings
中勾选Allow unsafe mode
- 在
ProjectSettings
的Player
的ScriptingDefineSymbols
添加ILRuntime
和DISABLE_ILRUNTIME_DEBUG
- 在
Assets
目录里建立一个名为smcs.rsp
的文本文件,并且写入内容-unsafe
使用
- 在项目里面创建程序集 Create->Assembly Definition
- 这里是IL
- 在项目的
Library\ScriptAssemblies
目录找到对应的程序集- IL.dll
- IL.pdb
- 在 Asset 目录创建一个目录 HotFix,把 IL.dll 和 IL.pdb 复制进去
委托
- 没跨域,可以正常直接使用
Action
和Func
- 如果跨域,带参数
Action
,通过appdomain.DelegateManager.RegisterMethodDelegate<参数类型>()
注册适配器 - 如果跨域,带参数
Func
,通过appdomain.DelegateManager.RegisterFunctionDelegate<参数类型,返回值>()
注册适配器 - 使用非系统级
Action
和Func
外的委托,需要进行委托转换处理DelegateConvertor
继承
- 没跨域,按正常使用继承
- 如果跨域,需要写适配器
CrossBindingAdaptor
并注册RegisterCrossBindingAdaptor
- 跨域继承的子类中,无法调用当前重载以为的虚函数
- 跨域继承中,不能在基类的构造函数中调用该类的虚函数
反射
- 默认情况下,
System.Reflection
命名空间中的方法,并不可能得知ILRuntime
中定义的类型,因此无法通过Type.GetType
等接口取得热更DLL里面的类型。而且ILRuntime
里的类型也并不是一个System.Type
。 - 在
ILRuntime
可用反射辅助类ILRuntimeType
ILRuntimeMethodInfo
ILRuntimeFieldInfo
- 在Unity主工程中不能通过
new T()
的方式来创建热更工程中的类型实例
CLR重定向
- 获取需要重定向的方法
- 编写重定向到新的方法
- 使用 appdomain.RegisterCLRMethodRedirection 注册重定向方法
CLR绑定
热更dll调用非热更代码时,减少gc使用。
- 添加导出脚本
- 编辑生成脚本
- InitializeILRuntime 使用 ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain); 初始化
调试
下载vs插件
https://github.com/Ourpalm/ILRuntime/releases/tag/v2.0.2
选择下载ILRuntimeDebuggerLauncher.vsix
,仅支持window初始化ilruntime的时候加上代码
1
appdomain.DebugService.StartDebugService(56000);
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添加
ILRuntime
和DISABLE_ILRUNTIME_DEBUG
在 Assets 目录里建立一个名为 smcs.rsp 的文本文件,并且写入内容 -unsafe
相关地址
ILRuntime-git
ILRuntime-home
ILRuntime学习项目代码
Unity资源热更及代码热更框架
ILRuntime来实现热更新的优与劣
protobuf3简化