更新日期:2020年3月11日。
Github源码:[点我获取源码]
以C#反射实现的轻量级热更新框架,开发非常方便,新项目只需要拉取框架源码后,一键即可创建热更新环境,之后便可以用C#正常开发,目前已支持热更新库与外界无障碍交互(无需实时反射),且可以动态修复外界任何方法(以热更新库中方法替换外界方法)。
注意:目前不支持IOS平台以及其他不支持JIT的平台,若要全平台支持可以使用可选模块ILHotfix。
1.对于新项目,如果要启用Hotfix,则直接在框架实体的Hotfix子物体上勾选IsEnableHotfix。
2.启用Hotfix之后,点击下面的Create Hotfix Environment按钮便可一键创建Hotfix环境。
3.创建完成后,面板会显示Hotfix环境已成功创建的提示,同时,红色外框标记的便为此项目中Hotfix代码的根目录,之后的Hotfix代码可以按照常规C#代码的方式编写,但必须放在此目录下才会被认为是Hotfix代码。
4.Hotfix环境目录非常简单:
A.Hotfix代码的根目录,新建的Hotfix脚本都必须放在此目录下。
→ HotfixEnvironment为自动生成的热更新环境类,理论上你不需要改其中任何代码,当然,也支持扩展它。
→ Hotfix.dll为我们热更的目标库(每次编译后会自动覆盖最新的),发布时只需将之打入指定AB包,并在B面板指定AB包名称及路径。
B.热更目标库打入的AB包名称及路径,如果没有特殊需求,这些可以保持默认值,热更目标库也始终放在A路径下。
创建完Hotfix环境后,我们直接运行就已经开始执行Hotfix逻辑了,只不过此时的Hotfix库为空,我们需要创建至少一个Hotfix流程(与主框架类似,流程也是Hotfix的生命周期)。
访问权限:Hotfix代码能正常访问外界代码,但任何地方都无法直接访问Hotfix代码,除非用反射!(或者修改一个设定就可以使外界代码直接访问Hotfix代码,但这样就失去了热更新库的可插拨性,丢失了热更新的本质)
推荐使用快捷创建方式:
Project界面右键 -> Create -> HTFramework -> C# HotfixProcedure Script
如下,我新建了一个名为Entrance的热更新流程,HotfixProcedureState.Entrance标记表明这是Hotfix逻辑的入口流程:
///
/// 新建热更新流程
///
[HotfixProcedureState(HotfixProcedureState.Entrance)]
public class Entrance : HotfixProcedureBase
{
///
/// 流程初始化
///
public override void OnInit()
{
GlobalTools.LogInfo("初始化 " + typeof(Entrance).Name + " 流程!");
}
///
/// 进入流程
///
public override void OnEnter()
{
GlobalTools.LogInfo("进入 " + typeof(Entrance).Name + " 流程!");
}
///
/// 离开流程
///
public override void OnLeave()
{
GlobalTools.LogInfo("离开 " + typeof(Entrance).Name + " 流程!");
}
///
/// 流程帧刷新
///
public override void OnUpdate()
{
Debug.Log(typeof(Entrance).Name + " 流程更新!");
}
///
/// 流程帧刷新(秒)
///
public override void OnUpdateSecond()
{
}
}
在新建一个普通的流程Normal:
///
/// 新建热更新流程
///
[HotfixProcedureState(HotfixProcedureState.Normal)]
public class Normal : HotfixProcedureBase
{
///
/// 流程初始化
///
public override void OnInit()
{
GlobalTools.LogInfo("初始化 " + typeof(Normal).Name + " 流程!");
}
///
/// 进入流程
///
public override void OnEnter()
{
GlobalTools.LogInfo("进入 " + typeof(Normal).Name + " 流程!");
}
///
/// 离开流程
///
public override void OnLeave()
{
GlobalTools.LogInfo("离开 " + typeof(Normal).Name + " 流程!");
}
///
/// 流程帧刷新
///
public override void OnUpdate()
{
Debug.Log(typeof(Normal).Name + " 流程更新!");
}
///
/// 流程帧刷新(秒)
///
public override void OnUpdateSecond()
{
}
}
我们在入口流程中切换流程:
///
/// 流程帧刷新
///
public override void OnUpdate()
{
Debug.Log(typeof(Entrance).Name + " 流程更新!");
//鼠标左键双击时切换流程
if (Main.m_Input.GetButtonDown(InputButtonType.MouseLeftDoubleClick))
{
//切换至 Normal 流程
HotfixEnvironment.Environment.SwitchProcedure<Normal>();
}
}
热更新必须使用AssetBundle加载模式,如果没有切换至该模式,将无法初始化热更新环境。
然后我们直接运行场景就可以了,确保勾选了IsEnableHotfix开关,否则将不启用Hotfix逻辑。
接下来我们双击左键,可以看到已经正确的切换了流程:
之后可以在Hotfix流程中扩展自己的代码,以及创建新的流程,不过,发布项目前务必确保最新的Hotfix库已经被打入了AB包中!
首先,Hotfix代码可以直接访问框架代码,但无法访问Assembly-CSharp程序集,若要使你的普通业务代码也可以被Hotfix直接访问,可以将你的普通代码统一到一个或多个程序集内,然后添加Hotfix程序集对你的程序集的引用,如下,我建立了一个程序集Test(Create -> Assembly definition),将你的代码全部放在Test所在的文件夹内:
注意:添加了新的程序集后,必须如下标记,将程序集加入到框架的运行时程序域,否则框架将不认识该程序集:
//将 Test 程序集加入框架运行时程序域(可以在任意非编辑器类中定义此字段)
[RunTimeAssembly]
private static string RuntimeAssembly = "Test";
然后添加Hotfix程序集对Test程序集的引用,之后Hotfix代码便可以无障碍访问Test中的代码:
同理,你也可以用如上的方法,添加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);
}
在编辑器中运行时将会出现运行时检视面板(Runtime Data),主要用以调试或数据监测,目前面板如下:
1.No Runtime Data!