XLua热更新代码

这篇简单的讲讲自己对XLua的一些理解,学习这一块的小伙伴肯定都知道用XLua的作用是什么,那就是对代码的热更新。下面就以一个最简单的demo来模拟用lua代码替换C#代码的过程。(相比热更,基本上就是少了从服务器下载lua代码的ab资源与ab资源的读取)。文章内容也是自己学习xlua的初步理解,有大佬们发现不对的望指正。Demo在MyExamples/Hotfix文件夹下。


首先我们新建一个脚本Hotfix.cs内容如下:

using UnityEngine;

namespace MyExamples {

    public class Hotfix : MonoBehaviour {

        void Start () {
            Show();
        }

        void Show() {
            Debug.Log("Show!!!");
        }
    }
}
脚本的内容很简单,就是运行的时候执行Show方法,打印一个log,然后这个应用就上线了。但是现在有一个需求,我们需要修改Show方法里面的log,但是我们又不想重新提交这个应用(毕竟出包审核可是很麻烦的,用户也不愿意老是更新应用)。这个时候就轮到Lua的登场了。当然了,下面这些处理操作都是需要在应用上线前添加好的。


相关官方文档:

热补丁:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md

XLua教程:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua%E6%95%99%E7%A8%8B.md


思路:利用xlua,我们可以访问执行lua代码。同时,xlua提供的lua的api  xlua.hotfix()可以修改C#里面指定的方法内容,也就是上面例子的Show方法。那么我们只需要在程序运行的时候访问lua代码,遍历看看有没有需要替换的C#方法即可。我们可以将每一个需要的更新补丁版本,写在同一个lua文件中。然后用一个数组存放这些文件名。程序启动的时候读取这个数组,若包含补丁文件,就执行对应的补丁lua脚本。(对于热更新而言,存放数组的lua文件和补丁文件都可以打成一个ab包放到服务器上,程序运行的时候下载读取这个ab的内容即可)


根据官方的建议,我们的lua代码都应该写在一个个的lua文件中,然后通过一个main.lua去统一调用处理。C#程序中只需要DoString("require 'main'")即可。根据需求和思路,我们可以有如下三个lua文件,放在Resources文件夹下:

main.lua:lua的入口,管理所有的lua的使用调用。

patchList.lua:存放补丁文件列表。

patch1.lua:补丁文件,也就是在这里面替换Show方法。

代码如下:

main.lua:

--lua的主文件,在这里面加载其他的lua脚本
print("main.lua   start");

-- 打补丁
local list = require("PatchList");
for _,filename in ipairs(list) do
    require(filename);
end

patchList.lua:

-- Lua 补丁的列表,只有加到此列表中的补丁才会加载。

return {
    "Patch1",
};

patch1.lua:

-- 补丁1

print("exe-----------patch1");

xlua.private_accessible(CS.MyExamples.Hotfix);  

xlua.hotfix(CS.MyExamples.Hotfix, "Show", function(self)  
    print("lua---Show");
end)

lua代码很简单,这儿就不细说了。接下来我们就要在C#中添加执行lua脚本的代码。LuaEnv建议的是全局就一个实例,并在Update中调用GC方法,完全不需要时调用Dispose。我们可以写一个单例来进行管理,XLuaManager.cs:

using XLua;

namespace MyExamples {

	public class XLuaManager {

        LuaEnv m_luaEnv;
        static XLuaManager m_instance;

        public static XLuaManager instance {
            get {
                if(m_instance == null) {
                    m_instance = new XLuaManager();
                }
                return m_instance;
            }
        }

        XLuaManager() {
            if(m_luaEnv == null) {
                m_luaEnv = new LuaEnv();
            }
        }

        public void Start() {
            m_luaEnv.DoString("require 'main'");
        }
    }
}

我们只需要在应用启动的时候执行里面的Start方法即可调起lua,demo里面就简单点,直接加在了Hotfix.cs的Start方法里面:

using UnityEngine;

namespace MyExamples {

    public class Hotfix : MonoBehaviour {

        void Start () {
            XLuaManager.instance.Start();
            Show();
        }

        void Show() {
            Debug.Log("Show!!!");
        }
    }
}

如果这个时候,执行Generate Code 和 Hotfix Inject In Editor后(如果没有Hotfix Inject In Editor选择,需要添加HOTFIX_ENABLE宏打开该特性,在Unity3D的File->Build Setting ->player settings...->Scripting Define Symbols下添加),运行程序,会发现有如下报错:


LuaException: xlua.access, no field __Hotfix0_Show

这个说明我们没有权限去修改,查看文档我们可以知道,我们还需要对要修改的代码添加[Hotfix]标签,这里我们按照官方推荐的白名单方式,在Editor文件夹下新建HotfixConfig.cs文件,对namespace进行白名单处理:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using XLua;

namespace MyExamples {

	public static class HotfixConfig {

        [Hotfix]
        public static List<Type> hotfixList {
            get {
                string[] allowNamespaces = new string[] {
                    "MyExamples",
                };

                return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
                        where allowNamespaces.Contains(type.Namespace)
                        select type).ToList();
            }
            
        }

    }
}

再执行Generate Code 和 Hotfix Inject In Editor后,运行程序。我们会发现,Show方法已经被修改了,美滋滋:



备注:有的童鞋可能在执行Hotfix Inject In Editor的时候,unity报错please install the Tools。这个是因为我们没有把xlua里面的Tools文件夹放到我们自己工程里面Assets的同级目录下。



补充:

有些小伙伴可能有这样的需求,就是我想热更一个方法的时候,还需要调用原方法(类似继承调用父方法)。按照上面的xlua.hotfix我们需要将原方法全部用lua重写一遍,这样很麻烦。xlua为我们提供了一个api来解决:util.hotfix_ex()。使用方法和hotfix一样,记得要require "xlua.util"。用self:methodName(...)来调用原方法

local util = require "xlua.util";
util.hotfix_ex(CS.MyExamples.Hotfix, "Show", function(self)
    self:Show();--调用原方法

    print("lua---Show");
end)

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值