UI是热更代码常应用到的地方之一。

我们在之前UIManager中将UI分离成了Panel、WindowBase、UIManager,其中的WindowBase负责了单个UI窗口的整个逻辑,是很适合热更的。

如果想要热更,我们首先要改变UI注册逻辑,在之前,我们在GameStart过程中注册了各个WindowBase

1
2
3
4
5
6
7
8
9
/// <summary>
/// 注册UI窗口
/// </summary>
void RegisterUI()
{
UIManager.Instance.Register<MenuWnd>(ConstantStr.MENUPANEL);
UIManager.Instance.Register<LoadingWnd>(ConstantStr.LOADINGPANEL);
UIManager.Instance.Register<HotFixWnd>(ConstantStr.HOTFIXPANEL);
}

如果想要热更,注册流程要转移到热更类中,并且在UIManager中修改WindowBase子类的实例化的方式。

准备

Unity自定义程序集可以全部被Assembly_CSharp.dll主程序集引用。但是反过来就不行了。所以为了能让UI热更,需要修改架构文件。

我们把ResFrame——Frames——UIFrm文件夹拖拽到Scripts文件夹下,并删除里面的“UIManager”这个程序集定义文件。

修改ILRuntimeManager

添加ILRunDomian属性,方便外部调用

1
public AppDomain ILRunDomain { get { return m_AppDomain; } }

修改HotFix工程

将Scripts——UGUI——Window文件夹内的LoadingWndMenuWnd剪切粘贴到HotFix工程内,然后再在工程的解决方案内“右键——添加”这两个文件。添加完成之后,给每个文件加上“HotFix”命名空间。

修改GameStart

修改GameStart注册窗口的方法,因为主工程获取不了热更工程中的WindowBase子类,所以我们改成直接注册WindowBase即可

1
2
3
4
5
6
void RegisterUI()
{
UIManager.Instance.Register<WindowBase>(ConstantStr.MENUPANEL);
UIManager.Instance.Register<WindowBase>(ConstantStr.LOADINGPANEL);
UIManager.Instance.Register<HotFixWnd>(ConstantStr.HOTFIXPANEL);
}

由于UI框架的设计,这里是必须要注册的,否则无法使用资源管理框架加载窗口资源。

修改UIManager

修改UIManagerCreateWindow方法,每当我们开启一个窗口时,先判断是否是从Resource加载,如果是,则从主工程域生成窗口实例;如果否,让热更域生成对应的窗口实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public WindowBase CreateWindow(string wndName,bool bTop = true,bool isFromResFolder = false,params object[] args)
{
WindowBase wnd = FindWindowByName<WindowBase>(wndName);
if (wnd == null)
{
System.Type tp = null;
if (m_RegisterDic.TryGetValue(wndName, out tp))//+++
{
if (isFromResFolder)
{
wnd = System.Activator.CreateInstance(tp) as WindowBase;
}
else
{
string hotName = "HotFix." + wndName.Replace("Panel.prefab", "Wnd");
wnd = ILRuntimeManager.Instance.ILRunDomain.Instantiate<WindowBase>(hotName);
wnd.IsHotFix = true;
wnd.HotFixClassName = hotName;
}
}
//...
}
//...
}

这里为了方便演示使用拼接字符串来获取hotName,在实际开发中,可以在GameStart注册阶段就将实际的类名注册进来(使用字典)。

修改WindowBase

修改WindowBase,给它添加IsHotFix属性和HotFixClassName属性。这是为了在窗口调用声明周期方法时,方便UIManager判断此窗口是否是热更窗口,从而更改调用路径。

1
2
3
4
5
6
7
8
/// <summary>
/// 是否是热更窗口
/// </summary>
public bool IsHotFix { get; set; } = false;
/// <summary>
/// 热更窗口在热更工程中的类名
/// </summary>
public string HotFixClassName { get; set; } = string.Empty;

修改UIManager各生命周期方法

修改UIManager的OnAwake、OnEnable、OnDisable、OnClose、OnUpdate等生命周期方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/// <summary>
/// 所有已打开窗口的更新
/// </summary>
public void OnUpdate()
{
for (int i = 0; i < m_WindowList.Count; i++)
{
WindowBase window = m_WindowList[i];
if (window != null)
{
if (window.IsHotFix)
{
ILRuntimeManager.Instance.ILRunDomain.Invoke(window.HotFixClassName, "OnUpdate", window);
}
else
{
window.OnUpdate();
}
}
}
}

仅作示意,各部分差别不大

注意OnMessage方法,这里没有修改OnMessage方法。这个方法一般在热更类内部自己调用,不需要使用UIManager