在ILRuntime里,使用Appdomain.Invoke
方法时,最后一个传入参数的地方不能传入参数数组(params object[]
)。所以我们要修改UI框架的传参方式
修改框架
修改UIManager
1 2 3
| public WindowBase CreateWindow(string wndName,bool bTop = true,bool isFromResFolder = false,object param1 = null,object param2 = null,object param3 = null); public void EnableWnd(string wndName,bool bTop = true, object param1 = null, object param2 = null, object param3 = null); public void EnableWnd(WindowBase wnd,bool bTop = true, object param1 = null, object param2 = null, object param3 = null);
|
其余的部分将param1、param2、param3三个参数传进来即可
修改WindowBase
修改WindowBase
的OnAwake
和OnEnable
方法
1 2
| public virtual void OnAwake(object param1 = null, object param2 = null, object param3 = null) { } public virtual void OnEnable(object param1 = null, object param2 = null, object param3 = null) { }
|
WindowBase适配器
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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| using ILRuntime.CLR.Method; using ILRuntime.Runtime.Enviorment; using ILRuntime.Runtime.Intepreter;
public class WindowBaseAdaptor : CrossBindingAdaptor { public override System.Type BaseCLRType => typeof(WindowBase);
public override System.Type AdaptorType => typeof(Adaptor);
public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance) { return new Adaptor(appdomain,instance); } class Adaptor : WindowBase, CrossBindingAdaptorType { AppDomain m_AppDomain; ILTypeInstance m_Instance; private object[] m_Paralist = new object[3]; IMethod m_OnAwakeMethod; IMethod m_OnEnableMethod; IMethod m_OnDisableMethod; IMethod m_OnUpdateMethod; IMethod m_OnCloseMethod; IMethod m_ToStringMethod; bool m_IsOnCloseInvoking = false; public Adaptor() { } public Adaptor(AppDomain appDomain,ILTypeInstance instance) { m_Instance = instance; m_AppDomain = appDomain; } public ILTypeInstance ILInstance => m_Instance;
public override void OnAwake(object param1 = null, object param2 = null, object param3 = null) { if (m_OnAwakeMethod == null) { m_OnAwakeMethod = m_Instance.Type.GetMethod("OnAwake", 3); } else { m_Paralist[0] = param1; m_Paralist[1] = param2; m_Paralist[2] = param3; m_AppDomain.Invoke(m_OnAwakeMethod, m_Instance, m_Paralist); } } public override void OnEnable(object param1 = null, object param2 = null, object param3 = null) { if (m_OnEnableMethod == null) { m_OnEnableMethod = m_Instance.Type.GetMethod("OnEnable", 3); } else { m_Paralist[0] = param1; m_Paralist[1] = param2; m_Paralist[2] = param3; m_AppDomain.Invoke(m_OnEnableMethod, m_Instance, m_Paralist); } } public override void OnDisable() { if (m_OnDisableMethod == null) { m_OnDisableMethod = m_Instance.Type.GetMethod("OnDisable", 0); } else { m_AppDomain.Invoke(m_OnDisableMethod, m_Instance); } } public override void OnClose() { if (m_OnCloseMethod == null) { m_OnCloseMethod = m_Instance.Type.GetMethod("OnClose", 0); } if (m_OnCloseMethod != null && !m_IsOnCloseInvoking) { m_IsOnCloseInvoking = true; m_AppDomain.Invoke(m_OnCloseMethod, m_Instance); m_IsOnCloseInvoking = false; } else { base.OnClose(); } } public override void OnUpdate() { if (m_OnUpdateMethod == null) { m_OnUpdateMethod = m_Instance.Type.GetMethod("OnUpdate", 0); } else { m_AppDomain.Invoke(m_OnUpdateMethod, m_Instance); } } public override string ToString() { if (m_ToStringMethod == null) { m_ToStringMethod = m_AppDomain.ObjectType.GetMethod("ToString", 0); } IMethod m = m_Instance.Type.GetVirtualMethod(m_ToStringMethod); if (m != null || m is ILMethod) { return m_Instance.ToString(); } else { return m_Instance.Type.FullName; }
} } }
|
我们在WindowBase
基类里面,对OnClose
方法有处理:
1 2 3 4 5 6 7
| public virtual void OnClose() { RemoveAllButtonListeners(); RemoveAllToggleListeners(); m_AllButton.Clear(); m_AllToggle.Clear(); }
|
这意味着,WindowBase
的子类肯定会调用base.OnClose
,而子类只要调用父类,我们的适配器就必须要写类似“m_IsOnCloseInvoking
”这样的方法。
我们梳理一下调用逻辑:
UIManager
——调用CloseWnd
——传到ILRuntime内部的方法——ILRuntime发现是跨域继承的子类——尝试调用WindowBase
适配器同名的方法——适配器调用OnClose,并且设置“m_IsOnCloseInvoking
”为true
——适配器又调用了ILRuntime内部的OnClose
方法——内部方法需要调用base.OnClose
——再次调用适配器的OnClose
,这时由于“m_IsOnCloseInvoking
”为true
,适配器进行了base.OnClose
的调用
修改HotFixWnd
修改HorFixWnd
报错的地方
1
| public override void OnAwake(object param1 = null, object param2 = null, object param3 = null)
|
修改HotFix工程内的报错
修改HotFix工程的报错,修改MenuWnd
1
| public override void OnAwake(object param1 = null,object param2 = null,object param3 = null)
|
修改LoadingWnd
1 2 3 4 5 6
| public override void OnAwake(object param1 = null, object param2 = null, object param3 = null) { m_LoadingPanel = GameObject.GetComponent<LoadingPanel>(); m_SceneName = param1.ToString(); GameSceneManager.Instance.OnSceneLoaded += LoadOtherSceneStartUI; }
|
进行CLR绑定
修改主工程的ILRuntimeCLRBinding
文件
1 2 3 4 5
| static void InitILRuntime(AppDomain domain) { domain.RegisterCrossBindingAdaptor(new WindowBaseAdaptor()); }
|
修改主工程的ILRuntimeManager
文件
1 2 3 4 5 6 7 8
| void InitializeILRuntime() { m_AppDomain.RegisterCrossBindingAdaptor(new WindowBaseAdaptor()); }
|
增加委托适配器
我们在WindowBase
里面添加过AddButtonClickListener
方法,Button.onClick.AddListener
方法对应的委托我们还没有注册,所以我们需要添加上。
我们在WindowBase
里面添加过OnLoadSpriteFinish
回调,代表异步加载完成的回调,我们也需要添加上
在ILRuntimeManager
的InitializeILRuntime
方法中添加新的委托适配器
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
| m_AppDomain.DelegateManager.RegisterMethodDelegate<System.String, UnityEngine.Object, System.Object, System.Object, System.Object>(); m_AppDomain.DelegateManager.RegisterDelegateConvertor<OnAsyncObjFinish>(action => { return new OnAsyncObjFinish((path, obj,param1,param2,param3) => { ((System.Action<System.String, UnityEngine.Object, System.Object, System.Object, System.Object>)action).Invoke(path, obj, param1, param2, param3); }); });
m_AppDomain.DelegateManager.RegisterMethodDelegate<bool>(); m_AppDomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<bool>>(action => { return new UnityEngine.Events.UnityAction<bool>((a) => { ((System.Action<bool>)action).Invoke(a); }); });
m_AppDomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>(action => { return new UnityEngine.Events.UnityAction(()=> { ((System.Action)action).Invoke(); }); });
|
测试
点击运行,看看是否进入了Menu场景,打开了Menu菜单