更新日期:2020年3月11日。
Github源码:​​​[点我获取源码]​​​ Gitee源码:​​[点我获取源码]​

索引

  • ​​Hotfix热更新模块简介​​
  • ​​使用Hotfix热更新​​
  • ​​创建Hotfix环境​​
  • ​​创建Hotfix流程​​
  • ​​设置资源加载模式​​
  • ​​运行​​
  • ​​Hotfix代码访问外界代码​​
  • ​​外界代码访问Hotfix代码​​
  • ​​热修复外界方法​​
  • ​​运行时检视面板​​

Hotfix热更新模块简介

以C#反射实现的轻量级热更新框架,开发非常方便,新项目只需要拉取框架源码后,一键即可创建热更新环境,之后便可以用C#正常开发,目前已支持热更新库与外界无障碍交互(无需实时反射),且可以动态修复外界任何方法(以热更新库中方法替换外界方法)

注意:目前不支持IOS平台以及其他不支持JIT的平台,若要全平台支持可以使用可选模块​​ILHotfix​​。

使用Hotfix热更新

创建Hotfix环境

1.对于新项目,如果要启用Hotfix,则直接在框架实体的Hotfix子物体上勾选IsEnableHotfix

【Unity】 HTFramework框架(十七)Hotfix热更新模块_Unity


2.启用Hotfix之后,点击下面的Create Hotfix Environment按钮便可一键创建Hotfix环境。

【Unity】 HTFramework框架(十七)Hotfix热更新模块_热修复_02


3.创建完成后,面板会显示Hotfix环境已成功创建的提示,同时,红色外框标记的便为此项目中Hotfix代码的根目录,之后的Hotfix代码可以按照常规C#代码的方式编写,但必须放在此目录下才会被认为是Hotfix代码。

【Unity】 HTFramework框架(十七)Hotfix热更新模块_热修复_03


4.Hotfix环境目录非常简单:

A.Hotfix代码的根目录,新建的Hotfix脚本都必须放在此目录下。
HotfixEnvironment为自动生成的热更新环境类,理论上你不需要改其中任何代码,当然,也支持扩展它。
Hotfix.dll为我们热更的目标库(每次编译后会自动覆盖最新的),发布时只需将之打入指定AB包,并在B面板指定AB包名称及路径。

B.热更目标库打入的AB包名称及路径,如果没有特殊需求,这些可以保持默认值,热更目标库也始终放在A路径下。

【Unity】 HTFramework框架(十七)Hotfix热更新模块_框架_04

创建Hotfix流程

创建完Hotfix环境后,我们直接运行就已经开始执行Hotfix逻辑了,只不过此时的Hotfix库为空,我们需要创建至少一个Hotfix流程(与主框架类似,流程也是Hotfix的生命周期)。

访问权限:Hotfix代码能正常访问外界代码,但任何地方都无法直接访问Hotfix代码,除非用反射!(或者修改一个设定就可以使外界代码直接访问Hotfix代码,但这样就失去了热更新库的可插拨性,丢失了热更新的本质)

推荐使用快捷创建方式:

Project界面右键 -> Create -> HTFramework -> C# HotfixProcedure Script

【Unity】 HTFramework框架(十七)Hotfix热更新模块_框架_05


如下,我新建了一个名为Entrance的热更新流程,HotfixProcedureState.Entrance标记表明这是Hotfix逻辑的入口流程:

/// <summary>
/// 新建热更新流程
/// </summary>
[HotfixProcedureState(HotfixProcedureState.Entrance)]
public class Entrance : HotfixProcedureBase
{
/// <summary>
/// 流程初始化
/// </summary>
public override void OnInit()
{
GlobalTools.LogInfo("初始化 " + typeof(Entrance).Name + " 流程!");
}

/// <summary>
/// 进入流程
/// </summary>
public override void OnEnter()
{
GlobalTools.LogInfo("进入 " + typeof(Entrance).Name + " 流程!");
}

/// <summary>
/// 离开流程
/// </summary>
public override void OnLeave()
{
GlobalTools.LogInfo("离开 " + typeof(Entrance).Name + " 流程!");
}

/// <summary>
/// 流程帧刷新
/// </summary>
public override void OnUpdate()
{
Debug.Log(typeof(Entrance).Name + " 流程更新!");
}

/// <summary>
/// 流程帧刷新(秒)
/// </summary>
public override void OnUpdateSecond()
{

}
}

在新建一个普通的流程Normal

/// <summary>
/// 新建热更新流程
/// </summary>
[HotfixProcedureState(HotfixProcedureState.Normal)]
public class Normal : HotfixProcedureBase
{
/// <summary>
/// 流程初始化
/// </summary>
public override void OnInit()
{
GlobalTools.LogInfo("初始化 " + typeof(Normal).Name + " 流程!");
}

/// <summary>
/// 进入流程
/// </summary>
public override void OnEnter()
{
GlobalTools.LogInfo("进入 " + typeof(Normal).Name + " 流程!");
}

/// <summary>
/// 离开流程
/// </summary>
public override void OnLeave()
{
GlobalTools.LogInfo("离开 " + typeof(Normal).Name + " 流程!");
}

/// <summary>
/// 流程帧刷新
/// </summary>
public override void OnUpdate()
{
Debug.Log(typeof(Normal).Name + " 流程更新!");
}

/// <summary>
/// 流程帧刷新(秒)
/// </summary>
public override void OnUpdateSecond()
{

}
}

我们在入口流程中切换流程:

/// <summary>
/// 流程帧刷新
/// </summary>
public override void OnUpdate()
{
Debug.Log(typeof(Entrance).Name + " 流程更新!");

//鼠标左键双击时切换流程
if (Main.m_Input.GetButtonDown(InputButtonType.MouseLeftDoubleClick))
{
//切换至 Normal 流程
HotfixEnvironment.Environment.SwitchProcedure<Normal>();
}
}

设置资源加载模式

热更新必须使用AssetBundle加载模式,如果没有切换至该模式,将无法初始化热更新环境。

【Unity】 HTFramework框架(十七)Hotfix热更新模块_框架_06

运行

然后我们直接运行场景就可以了,确保勾选了IsEnableHotfix开关,否则将不启用Hotfix逻辑。

【Unity】 HTFramework框架(十七)Hotfix热更新模块_热修复_07


接下来我们双击左键,可以看到已经正确的切换了流程:

【Unity】 HTFramework框架(十七)Hotfix热更新模块_热修复_08


之后可以在Hotfix流程中扩展自己的代码,以及创建新的流程,不过,发布项目前务必确保最新的Hotfix库已经被打入了AB包中!

Hotfix代码访问外界代码

首先,Hotfix代码可以直接访问框架代码,但无法访问Assembly-CSharp程序集,若要使你的普通业务代码也可以被Hotfix直接访问,可以将你的普通代码统一到一个或多个程序集内,然后添加Hotfix程序集对你的程序集的引用,如下,我建立了一个程序集Test(Create -> Assembly definition),将你的代码全部放在Test所在的文件夹内:

【Unity】 HTFramework框架(十七)Hotfix热更新模块_框架_09


注意:添加了新的程序集后,必须如下标记,将程序集加入到框架的运行时程序域,否则框架将不认识该程序集:

//将 Test 程序集加入框架运行时程序域(可以在任意非编辑器类中定义此字段)
[RunTimeAssembly]
private static string RuntimeAssembly = "Test";

然后添加Hotfix程序集对Test程序集的引用,之后Hotfix代码便可以无障碍访问Test中的代码:

【Unity】 HTFramework框架(十七)Hotfix热更新模块_Unity_10

外界代码访问Hotfix代码

同理,你也可以用如上的方法,添加Test程序集对Hotfix程序集的引用,使Test代码无障碍访问Hotfix代码,不过这样的话你的项目将无法发布,因为Hotfix代码是动态加入的,编辑器切换到RunTime模式后,Test程序集中的代码将找不到Hotfix程序集。

所以外界代码访问Hotfix代码推荐使用反射方式,如下例子:

//【外界代码】
//从 Main.m_Hotfix.HotfixAssembly 反射,热更新程序集
Type type = Main.m_Hotfix.HotfixAssembly.GetType("HotfixEnvironment");
MethodInfo method = type.GetMethod("TestMethod", BindingFlags.Static | BindingFlags.Public);
method.Invoke(null, null);

//从 Main.m_Hotfix.HotfixEnvironment 反射,热更新环境
method = Main.m_Hotfix.HotfixEnvironment.GetType().GetMethod("TestMethod", BindingFlags.Static | BindingFlags.Public);
method.Invoke(null, null);

热修复外界方法

Hotfix支持运行时热修复外界任何方法,也即是运行时使用热更新库中的方法,替换外界的任何方法,当在项目上线后某些方法出现了BUG时,便可以在热更新库中修复替换该方法,无需重新发布项目,只需更新Hotfix库即可,待到下次项目版本大更新时,再修复项目中的原方法。

要使用热修复方法功能,外界方法必须在热修复模式下调用:

//【外界代码】
public HTFAction OriginalMethodFix;

private void OriginalMethod()
{
GlobalTools.LogInfo("这是原始方法。");
}

private void Awake()
{
//使用热修复模式
OriginalMethodFix = Main.m_Hotfix.FixMethod(OriginalMethod);
//热修复后的方法
OriginalMethodFix();
}

然后Hotfix代码中用于替换的方法还需要添加一个标记:

//【Hotfix代码】
//热修复标记,必须标记目标的完整类名及方法名,中间用.连接
[HotfixMethod("TestProcedure.OriginalMethod")]
private static void FixMethod()
{
GlobalTools.LogInfo("这是修复后的方法。");
}

使用热修复模式运行方法会有些许消耗,所以可以将修复后的方法保存下来,后面直接使用,当然,当热更新未启用时,使用修复模式运行方法也不会有多余的开销,所以不用担心。

热修复模式支持重载方法:

//【外界代码】
private void Awake()
{
//使用热修复模式
Main.m_Hotfix.FixMethod(OriginalMethod)();
Main.m_Hotfix.FixMethod<string>(OriginalMethod)("a");
Main.m_Hotfix.FixMethod<string, string>(OriginalMethod)("a", "b");
}

private void OriginalMethod()
{
GlobalTools.LogInfo("这是原始方法。");
}

private void OriginalMethod(string arg)
{
GlobalTools.LogInfo("这是原始方法。参数:" + arg);
}

private void OriginalMethod(string arg1, string arg2)
{
GlobalTools.LogInfo("这是原始方法。参数1:" + arg1 + " 参数2:" + arg2);
}
//【Hotfix代码】
//热修复标记,必须标记目标的完整类名及方法名,中间用.连接
[HotfixMethod("TestProcedure.OriginalMethod")]
private static void FixMethod()
{
GlobalTools.LogInfo("这是修复后的方法。");
}

[HotfixMethod("TestProcedure.OriginalMethod")]
private static void FixMethod(string arg)
{
GlobalTools.LogInfo("这是修复后的方法。参数:" + arg);
}

[HotfixMethod("TestProcedure.OriginalMethod")]
private static void FixMethod(string arg1, string arg2)
{
GlobalTools.LogInfo("这是修复后的方法。参数1:" + arg1 + " 参数2:" + arg2);
}

在未启用热更新时,运行:

【Unity】 HTFramework框架(十七)Hotfix热更新模块_热更新_11


启用热更新后,运行:

【Unity】 HTFramework框架(十七)Hotfix热更新模块_热修复_12

运行时检视面板

在编辑器中运行时将会出现运行时检视面板(Runtime Data),主要用以调试或数据监测,目前面板如下:

【Unity】 HTFramework框架(十七)Hotfix热更新模块_Unity_13


1.No Runtime Data!