Unity ILRuntime 调用方法一览


Unity C#热更新方案 ILRuntime学习笔记

 

一、主工程调用Hotfix代码

假设Hotfix工程里有一个Test类,该如何调用该类的方法呢?

namespace Hotfix { public class Test { // 实例方法 public string GetName() { return "test"; } // 静态方法 public static float Sum(float a, float b) { return a + b; } } }

1.调用静态方法

// 获取类型 IType type = appdomain.LoadedTypes["Hotfix.Test"]; // 获取方法 IMethod method = type.GetMethod("Sum", 2); // 调用方法 object returnValue = appdomain.Invoke(method, null, 1, 2); // 输出返回值 print("静态方法返回值:" + returnValue);

2.调用实例方法

// 获取类型 IType type = appdomain.LoadedTypes["Hotfix.Test"]; // 创建实例 object instance = (type as ILType).Instantiate(); // 获取方法 IMethod method = type.GetMethod("GetName", 0); // 调用方法 object returnValue = appdomain.Invoke(method, instance); // 输出返回值 print("静态方法返回值:" + returnValue);

二、Hotfix调用主工程代码

Hotfix调用主工程代码直接调用即可,无需特别步骤。

namespace Hotfix { using UnityEngine; public class Test { // 调用主工程方法 private void CallUnity() { Debug.Log(Application.streamingAssetsPath); } } }

三、Hotfix响应MonoBehaviour事件

Hotfix响应MonoBehaviour中的事件,可以用代理方法实现。

1.在Unity中新建一个Mono脚本,实现自己需要的接口,在这些接口被调用时,调用代理事件

namespace GameUtils.Triggers { using System; using UnityEngine; /// <summary> /// <para>MonoBehaviour 基本事件触发器 触发以下事件</para> /// OnEnable、Start、OnDisable、OnDestroy /// </summary> public class MonoBehaviourEventTrigger : MonoBehaviour { public Action onEnable; public Action start; public Action update public Action onDisable; public Action onDestroy; private void OnEnable() { if (onEnable != null) onEnable.Invoke(); } private void Start() { if (start != null) start.Invoke(); } private void OnDisable() { if (onDisable != null) onDisable.Invoke(); } private void Update() { if (update != null) update.Invoke(); } private void OnDestroy() { if (onDestroy != null) onDestroy.Invoke(); } } }

2.在Hotfix工程中这样调用:

namespace Hotfix { using UnityEngine; using GameUtils.Triggers; public class Test { private void MonoTest() { GameObject obj = new GameObject("Test"); MonoBehaviourEventTrigger monoTrigger = obj.AddComponent<MonoBehaviourEventTrigger>(); monoTrigger.start = Start; monoTrigger.update = Update; monoTrigger.onDestroy = OnDestroy; } private void Start() { Debug.Log("Start"); } private void Update() { // 鼠标按下时,做射线碰撞检测 if (Input.GetMouseButtonDown(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 1000)) { Debug.Log(hit.point); } } } private void OnDestroy() { Debug.Log("OnDestroy"); } } }

注:由于Mono接口是主工程中的,不能热更,所以要提前写好所有接口以供热更代码调用。Mono中的接口众多,如果全部用一个类实现的话太过冗余,我这里做了一下优化,把不同功能的接口分组到不同的脚本中,由一个统一的Mono根据调用情况动态添加,在set里实现调用时的动态添加脚本功能,使用时还是一样方便,代码太长就不贴了。

3.带参数的Action

注意,带参数的Action在跨域调用前要在主工程里注册参数。
否则调用会报错。

private void RegistDelegate() { DelegateManager manager = appdomain.DelegateManager; manager.RegisterMethodDelegate<bool>(); manager.RegisterMethodDelegate<byte>(); manager.RegisterMethodDelegate<sbyte>(); manager.RegisterMethodDelegate<char>(); manager.RegisterMethodDelegate<short>(); manager.RegisterMethodDelegate<ushort>(); manager.RegisterMethodDelegate<int>(); manager.RegisterMethodDelegate<uint>(); manager.RegisterMethodDelegate<long>(); manager.RegisterMethodDelegate<ulong>(); manager.RegisterMethodDelegate<float>(); manager.RegisterMethodDelegate<double>(); manager.RegisterMethodDelegate<string>(); manager.RegisterMethodDelegate<object>(); manager.RegisterMethodDelegate<Collider>(); manager.RegisterMethodDelegate<Collision>(); manager.RegisterMethodDelegate<BaseEventData>(); manager.RegisterMethodDelegate<PointerEventData>(); manager.RegisterMethodDelegate<Object>(); manager.RegisterMethodDelegate<GameObject>(); appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>((action) => { return new UnityEngine.Events.UnityAction(() => { ((System.Action)action)(); }); }); }

四、跨域调用性能优化

跨域调用的性能是很差的。性能优化的方式如下:

1.主工程调用Hotfix时,多用type.GetMethod()去调用。

// 1.用string调用方法: appdomain.Invoke("Hotfix.Test", "Sum", null, null); // 2.用Method调用方法性能更好 IType type = appdomain.LoadedTypes["Hotfix.Test"]; IMethod method = type.GetMethod("Sum", 2); appdomain.Invoke(method, instance, 1, 2);

2.Hotfix调用主工程代码时,可以用CLRBinding优化。

官方提供了一个工具,可以实现Hotfix调用的优化,该工具会自动分析热更dll中调用的方法,自动生成CLRBinding类。

使用方式是:在unity顶部菜单中选择ILRuntime > Generate CLR Binding Code by Analysis

CLRBinding.png

当然,使用前要配置你热更dll的路径和生成文件的路径。
在Unity查找ILRuntimeCLRBinding这个类,修改其中路径。

#if UNITY_EDITOR using UnityEditor; using UnityEngine; using System; using System.Text; using System.Collections.Generic; using ILRuntimeDemo; [System.Reflection.Obfuscation(Exclude = true)] public class ILRuntimeCLRBinding { [MenuItem("ILRuntime/Generate CLR Binding Code by Analysis")] static void GenerateCLRBindingByAnalysis() { //用新的分析热更dll调用引用来生成绑定代码 ILRuntime.Runtime.Enviorment.AppDomain domain = new ILRuntime.Runtime.Enviorment.AppDomain(); using (System.IO.FileStream fs = new System.IO.FileStream("Assets/StreamingAssets/Hotfix.dll", System.IO.FileMode.Open, System.IO.FileAccess.Read)) { domain.LoadAssembly(fs); //Crossbind Adapter is needed to generate the correct binding code InitILRuntime(domain); ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(domain, "Assets/Game/ILRuntime/Generated"); } AssetDatabase.Refresh(); } static void InitILRuntime(ILRuntime.Runtime.Enviorment.AppDomain domain) { //这里需要注册所有热更DLL中用到的跨域继承Adapter,否则无法正确抓取引用 domain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter()); domain.RegisterCrossBindingAdaptor(new CoroutineAdapter()); domain.RegisterCrossBindingAdaptor(new TestClassBaseAdapter()); domain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder()); } } #endif

总结:
主工程调用Hotfix代码时比较麻烦,要用类似反射的形式。
Hotfix调用主工程代码很容易,正常怎么写就怎么写。
Hotfix调用MonoBehaviour的接口可以用代理的方式。
调用时要注意性能问题,可以进行优化。

转发自:  https://segmentfault.com/a/1190000023290547    感谢冰封百度大佬

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM