ILRuntime使用调试器 基于TCP的调试,没有机器限制,可以调试本地,也可以调试真机。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void InitializeILRuntime ( ) { …… appdomain.DebugService.StartDebugService(56000 ); } IEnumerator WaitDebuggerAndRun ( ) { Debug.Log("等待调试器连接" ); while (!appdomain.DebugService.IsDebuggerAttached) { yield return null ; } yield return new WaitForSeconds (1 ) ; OnHotFixLoaded(); }
ILRuntime使用委托 在热更里面创建的委托实例,传到主工程的变量里,称为委托实例的跨域。这种情况需要在主工程注册适配器才能正常运行。 1.由于IL2CPP的特性,使用到不同参数组合的委托需要注册委托适配器、 2.如果使用非Action/Func类型委托,需要注册委托转换器。 3.尽量避免不必要的跨域委托调用。 4.尽量使用Action/Func这两个万能委托类型。
DelegateDemo.cs 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public delegate void TestDelegateMethod (int a ) ;public delegate string TestDelegateFunction (int a ) ;public class DelegateDemo : MonoBehaviour { public static TestDelegateMethod TestMethodDelegate; public static TestDelegateFunction TestFunctionDelegate; public static System.Action<string > TestActionDelegate; void InitializeILRuntime ( ) { #if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE) appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId; #endif appdomain.DelegateManager.RegisterMethodDelegate<int >(); appdomain.DelegateManager.RegisterFunctionDelegate<int , string >(); appdomain.DelegateManager.RegisterMethodDelegate<string >(); appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => { return new TestDelegateMethod((a) => { ((System.Action<int >)action)(a); }); }); appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) => { return new TestDelegateFunction((a) => { return ((System.Func<int , string >)action)(a); }); }); appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float >>((action) => { return new UnityEngine.Events.UnityAction<float >((a) => { ((System.Action<float >)action)(a); }); }); } void OnHotFixLoaded ( ) { Debug.Log("完全在热更DLL内部使用的委托,直接可用,不需要做任何处理" ); Debug.Log("如果需要跨域调用委托(将热更DLL里面的委托实例传到Unity主工程用), 就需要注册适配器" ); Debug.Log("这是因为iOS的IL2CPP模式下,不能动态生成类型,为了避免出现不可预知的问题,我们没有通过反射的方式创建委托实例,因此需要手动进行一些注册" ); Debug.Log("如果没有注册委托适配器,运行时会报错并提示需要的注册代码,直接复制粘贴到ILRuntime初始化的地方" ); appdomain.Invoke("HotFix_Project.TestDelegate" , "Initialize2" , null , null ); appdomain.Invoke("HotFix_Project.TestDelegate" , "RunTest2" , null , null ); Debug.Log("运行成功,我们可以看见,用Action或者Func当作委托类型的话,可以避免写转换器,所以项目中在不必要的情况下尽量只用Action和Func" ); Debug.Log("另外应该尽量减少不必要的跨域委托调用,如果委托只在热更DLL中用,是不需要进行任何注册的" ); Debug.Log("---------" ); Debug.Log("我们再来在Unity主工程中调用一下刚刚的委托试试" ); TestMethodDelegate(789 ); var str = TestFunctionDelegate(098 ); Debug.Log("!! OnHotFixLoaded str = " + str); TestActionDelegate("Hello From Unity Main Project" ); } }
HotFix_Project.TestDelegate 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 namespace HotFix_Project { public class TestDelegate { static TestDelegateMethod delegateMethod; static TestDelegateFunction delegateFunc; static Action<string > delegateAction; public static void Initialize ( ) { delegateMethod = Method; delegateFunc = Function; delegateAction = Action; } public static void RunTest ( ) { delegateMethod(123 ); var res = delegateFunc(456 ); UnityEngine.Debug.Log("!! TestDelegate.RunTest res = " + res); delegateAction("rrr" ); } public static void Initialize2 ( ) { DelegateDemo.TestMethodDelegate = Method; DelegateDemo.TestFunctionDelegate = Function; DelegateDemo.TestActionDelegate = Action; } public static void RunTest2 ( ) { DelegateDemo.TestMethodDelegate(123 ); var res = DelegateDemo.TestFunctionDelegate(456 ); UnityEngine.Debug.Log("!! TestDelegate.RunTest2 res = " + res); DelegateDemo.TestActionDelegate("rrr" ); } static void Method (int a ) { UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a); } static string Function (int a ) { return a.ToString(); } static void Action (string a ) { UnityEngine.Debug.Log("!! TestDelegate.Action, a = " + a); } } }
在ILRuntime继承主工程 ILRuntime中跨域继承
1.热更DLL中继承Unity主工程的类型称为跨域继承。 2.跨域继承需要编写跨域继承适配器。 3.热更DLL不能同时继承或实现1个以上主工程的类型或接口。 4.尽量避免跨域继承,尤其避免继承MonoBehaviour。
Inheritance.cs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void OnHotFixLoaded ( ) { Debug.Log("首先我们来创建热更里的类实例" ); TestClassBase obj; Debug.Log("现在我们来注册适配器, 该适配器由ILRuntime/Generate Cross Binding Adapter菜单命令自动生成" ); appdomain.RegisterCrossBindingAdaptor(new TestClassBaseAdapter()); Debug.Log("现在再来尝试创建一个实例" ); obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance" ); Debug.Log("现在来调用成员方法" ); obj.TestAbstract(123 ); obj.TestVirtual("Hello" ); obj.Value = 233 ; Debug.LogFormat("obj.Value={0}" , obj.Value); Debug.Log("现在换个方式创建实例" ); obj = appdomain.Invoke("HotFix_Project.TestInheritance" , "NewObject" , null , null ) as TestClassBase; obj.TestAbstract(456 ); obj.TestVirtual("Foobar" ); obj.Value = 2333333 ; Debug.LogFormat("obj.Value={0}" , obj.Value); }
主工程TestClassBase 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public abstract class TestClassBase { public virtual int Value { get { return 0 ; } set { } } public virtual void TestVirtual (string str ) { Debug.Log("!! TestClassBase.TestVirtual, str = " + str); } public abstract void TestAbstract (int gg ) ; }
适配器InheritanceAdapter.cs 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 public class TestClassBaseAdapter : CrossBindingAdaptor { static CrossBindingFunctionInfo <System.Int32 > mget_Value_0 = new CrossBindingFunctionInfo<System.Int32>("get_Value" ); static CrossBindingMethodInfo <System.Int32 > mset_Value_1 = new CrossBindingMethodInfo<System.Int32>("set_Value" ); static CrossBindingMethodInfo <System.String > mTestVirtual_2 = new CrossBindingMethodInfo<System.String>("TestVirtual" ); static CrossBindingMethodInfo <System.Int32 > mTestAbstract_3 = new CrossBindingMethodInfo<System.Int32>("TestAbstract" ); public override Type BaseCLRType { get { return typeof (global ::TestClassBase); } } public override Type AdaptorType { get { return typeof (Adapter); } } public override object CreateCLRInstance (ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance ) { return new Adapter(appdomain, instance); } public class Adapter : global ::TestClassBase , CrossBindingAdaptorType { ILTypeInstance instance; ILRuntime.Runtime.Enviorment.AppDomain appdomain; public Adapter ( ) { } public Adapter (ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance ) { this .appdomain = appdomain; this .instance = instance; } public ILTypeInstance ILInstance { get { return instance; } } public override void TestVirtual (System.String str ) { if (mTestVirtual_2.CheckShouldInvokeBase(this .instance)) base .TestVirtual(str); else mTestVirtual_2.Invoke(this .instance, str); } public override void TestAbstract (System.Int32 gg ) { mTestAbstract_3.Invoke(this .instance, gg); } public override System.Int32 Value { get { if (mget_Value_0.CheckShouldInvokeBase(this .instance)) return base .Value; else return mget_Value_0.Invoke(this .instance); } set { if (mset_Value_1.CheckShouldInvokeBase(this .instance)) base .Value = value ; else mset_Value_1.Invoke(this .instance, value ); } } public override string ToString ( ) { IMethod m = appdomain.ObjectType.GetMethod("ToString" , 0 ); m = instance.Type.GetVirtualMethod(m); if (m == null || m is ILMethod) { return instance.ToString(); } else return instance.Type.FullName; } } }
HotFix_Project.TestInheritance 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class TestInheritance : TestClassBase { public override int Value { get ; set ; } public override void TestAbstract (int gg ) { UnityEngine.Debug.Log("!! TestInheritance.TestAbstract gg =" + gg); } public override void TestVirtual (string str ) { base .TestVirtual(str); UnityEngine.Debug.Log("!! TestInheritance.TestVirtual str =" + str); } public static TestInheritance NewObject ( ) { return new HotFix_Project.TestInheritance(); } }