这篇简单的讲讲自己对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)
复制代码 |