找回密码
 立即注册
查看: 333|回复: 0

XLua热更新代码

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

首先我们新建一个脚本Hotfix.cs内容如下:
  1. using UnityEngine;
  2. namespace MyExamples {
  3.     public class Hotfix : MonoBehaviour {
  4.         void Start () {
  5.             Show();
  6.         }
  7.         void Show() {
  8.             Debug.Log("Show!!!");
  9.         }
  10.     }
  11. }
复制代码
脚本的内容很简单,就是运行的时候执行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:
  1. --lua的主文件,在这里面加载其他的lua脚本
  2. print("main.lua   start");
  3. -- 打补丁
  4. local list = require("PatchList");
  5. for _,filename in ipairs(list) do
  6.     require(filename);
  7. end
复制代码
patchList.lua:
  1. -- Lua 补丁的列表,只有加到此列表中的补丁才会加载。
  2. return {
  3.     "Patch1",
  4. };
复制代码
patch1.lua:
  1. -- 补丁1
  2. print("exe-----------patch1");
  3. xlua.private_accessible(CS.MyExamples.Hotfix);  
  4. xlua.hotfix(CS.MyExamples.Hotfix, "Show", function(self)  
  5.     print("lua---Show");
  6. end)
复制代码
lua代码很简单,这儿就不细说了。接下来我们就要在C#中添加执行lua脚本的代码。LuaEnv建议的是全局就一个实例,并在Update中调用GC方法,完全不需要时调用Dispose。我们可以写一个单例来进行管理,XLuaManager.cs:
  1. using XLua;
  2. namespace MyExamples {
  3.         public class XLuaManager {
  4.         LuaEnv m_luaEnv;
  5.         static XLuaManager m_instance;
  6.         public static XLuaManager instance {
  7.             get {
  8.                 if(m_instance == null) {
  9.                     m_instance = new XLuaManager();
  10.                 }
  11.                 return m_instance;
  12.             }
  13.         }
  14.         XLuaManager() {
  15.             if(m_luaEnv == null) {
  16.                 m_luaEnv = new LuaEnv();
  17.             }
  18.         }
  19.         public void Start() {
  20.             m_luaEnv.DoString("require 'main'");
  21.         }
  22.     }
  23. }
复制代码
我们只需要在应用启动的时候执行里面的Start方法即可调起lua,demo里面就简单点,直接加在了Hotfix.cs的Start方法里面:
  1. using UnityEngine;
  2. namespace MyExamples {
  3.     public class Hotfix : MonoBehaviour {
  4.         void Start () {
  5.             XLuaManager.instance.Start();
  6.             Show();
  7.         }
  8.         void Show() {
  9.             Debug.Log("Show!!!");
  10.         }
  11.     }
  12. }
复制代码
如果这个时候,执行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进行白名单处理:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using XLua;
  6. namespace MyExamples {
  7.         public static class HotfixConfig {
  8.         [Hotfix]
  9.         public static List<Type> hotfixList {
  10.             get {
  11.                 string[] allowNamespaces = new string[] {
  12.                     "MyExamples",
  13.                 };
  14.                 return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
  15.                         where allowNamespaces.Contains(type.Namespace)
  16.                         select type).ToList();
  17.             }
  18.             
  19.         }
  20.     }
  21. }
复制代码
再执行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(...)来调用原方法
  1. local util = require "xlua.util";
  2. util.hotfix_ex(CS.MyExamples.Hotfix, "Show", function(self)
  3.     self:Show();--调用原方法
  4.     print("lua---Show");
  5. end)
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 08:31 , Processed in 0.091263 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表