在ILRuntime中挟持主工程方法(CLR重定向)
1.有些主工程的方法和接口无法正常处理热更DLL里的类型和对象。
2.CLR重定向可以对这些方法进行挟持。
3.重定向方法需要理解IL底层机制,建议参考CLR绑定生成的代码。
1 2 3 4 5 6 7 8 9 10
| unsafe void InitializeILRuntime() { #if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE) appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId; #endif var mi = typeof(Debug).GetMethod("Log", new System.Type[] { typeof(object) }); appdomain.RegisterCLRMethodRedirection(mi, Log_11); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
unsafe static StackObject* Log_11(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj) { ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain; StackObject* ptr_of_this_method; StackObject* __ret = ILIntepreter.Minus(__esp, 1); ptr_of_this_method = ILIntepreter.Minus(__esp, 1);
object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack)); __intp.Free(ptr_of_this_method);
var stacktrace = __domain.DebugService.GetStackTrace(__intp);
UnityEngine.Debug.Log(message + "\n" + stacktrace);
return __ret; }
|
1 2 3 4 5 6 7 8 9 10
| unsafe void OnHotFixLoaded() { Debug.Log("什么时候需要CLR重定向呢,当我们需要挟持原方法实现,添加一些热更DLL中的特殊处理的时候,就需要CLR重定向了"); Debug.Log("详细文档请参见Github主页的相关文档"); Debug.Log("CLR重定向对ILRuntime底层实现密切相关,因此要完全理解这个Demo,需要大家先看关于ILRuntime实现原理的Demo"); Debug.Log("下面介绍一个CLR重定向的典型用法,比如我们在DLL里调用Debug.Log,默认情况下是无法显示DLL内堆栈的"); Debug.Log("但是经过CLR重定向之后可以做到输出DLL内堆栈,接下来进行CLR重定向注册"); Debug.Log("请注释和解除InitializeILRuntime方法里的重定向注册,对比下一行日志的变化"); appdomain.Invoke("HotFix_Project.TestCLRRedirection", "RunTest", null, null); }
|
提升热更调用主工程方法的性能
CLR绑定
1.默认情况调用主工程接口会使用反射来调用。
2.性能较低,且IL2CPP环境下容易被剪裁。
3.ILRuntime提供了自动分析生成绑定的工具。
4.每次出包前一定得记得生成CLR绑定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void InitializeILRuntime() { #if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE) appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId; #endif
ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain); }
|
提升使用值类型的性能
1 2 3 4 5 6 7 8 9 10 11
| void InitializeILRuntime() { #if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE) appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId; #endif appdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder()); appdomain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder()); appdomain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder()); }
|
在ILRuntime使用异步操作
协程和异步操作的使用
1.协程和异步都能在ILRuntime中使用。
2.编译器会自动生成继承系统接口的匿名类造成跨域继承。
3.使用跨域继承器适配器可以完成异步操作的适配。
4.避免在异步操作中使用foreach。
1 2 3 4 5 6 7 8 9 10 11
| void InitializeILRuntime() { #if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE) appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId; #endif appdomain.RegisterCrossBindingAdaptor(new CoroutineAdapter()); appdomain.DebugService.StartDebugService(56000); }
|