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

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

索引

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

Hotfix热更新模块简介

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

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

使用Hotfix热更新

创建Hotfix环境

1.对于新项目,如果要启用Hotfix,则直接在框架实体的Hotfix子物体上勾选IsEnableHotfix
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第1张图片
2.启用Hotfix之后,点击下面的Create Hotfix Environment按钮便可一键创建Hotfix环境。
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第2张图片
3.创建完成后,面板会显示Hotfix环境已成功创建的提示,同时,红色外框标记的便为此项目中Hotfix代码的根目录,之后的Hotfix代码可以按照常规C#代码的方式编写,但必须放在此目录下才会被认为是Hotfix代码。
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第3张图片
4.Hotfix环境目录非常简单:

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

B.热更目标库打入的AB包名称及路径,如果没有特殊需求,这些可以保持默认值,热更目标库也始终放在A路径下。
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第4张图片

创建Hotfix流程

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

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

推荐使用快捷创建方式:
Project界面右键 -> Create -> HTFramework -> C# HotfixProcedure Script
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第5张图片
如下,我新建了一个名为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逻辑。
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第6张图片
接下来我们双击左键,可以看到已经正确的切换了流程:
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第7张图片
之后可以在Hotfix流程中扩展自己的代码,以及创建新的流程,不过,发布项目前务必确保最新的Hotfix库已经被打入了AB包中!

Hotfix代码访问外界代码

首先,Hotfix代码可以直接访问框架代码,但无法访问Assembly-CSharp程序集,若要使你的普通业务代码也可以被Hotfix直接访问,可以将你的普通代码统一到一个或多个程序集内,然后添加Hotfix程序集对你的程序集的引用,如下,我建立了一个程序集Test(Create -> Assembly definition),将你的代码全部放在Test所在的文件夹内:
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第8张图片
注意:添加了新的程序集后,必须如下标记,将程序集加入到框架的运行时程序域,否则框架将不认识该程序集:

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

然后添加Hotfix程序集对Test程序集的引用,之后Hotfix代码便可以无障碍访问Test中的代码:
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第9张图片

外界代码访问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热更新模块_第10张图片
启用热更新后,运行:
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第11张图片

运行时检视面板

在编辑器中运行时将会出现运行时检视面板(Runtime Data),主要用以调试或数据监测,目前面板如下:
【Unity】 HTFramework框架(十七)Hotfix热更新模块_第12张图片
1.No Runtime Data!

你可能感兴趣的:(Unity,Unity,HTFramework,Unity,Editor,Develop)