RedZero9 发表于 2021-8-14 13:39

XLua 热更新方案

1、下载XLua最新框架zip(https://github.com/Tencent/xLua)
2、导入最新的XLua框架(按文件原始路径,导入Plugins、XLua、Tool三个文件)
(1)项目Asset目录下导入Plugings和XLua;
(2)Asset同级目录下导入Tool工具;
(3)开启宏 HOTFIX_ENABLE,File---->buildSetting---->playerSetting---->scriptsDefineSymbols里添加;HOTFIX_ENABLE。(注意 :编辑器、各手机平台这个宏要分别设置!如果是自动化打包,要注意在代码里头用API设置的宏是不生效的,需要在编辑器设置)


3、C#逻辑下热更新逻辑入口(可以放在Camera下或在检测版本后激活该脚本)
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;

public class FishHotFix_Inlet : MonoBehaviour
{
    LuaEnv luaenv = null;

    void Start()
    {
      luaenv = new LuaEnv();

      //luaenv.DoString("print('hello world')");


      //luaenv.DoString("require 'fishHotFixPrint'");


      //luaenv.DoString(@"
      //    xlua.hotfix(CS.Inlet, 'FTest', function(self)
      //      print('inlet .. hotfix .. FTest')
      //    end)
      //");


      //luaenv.DoString("require 'fishHotFix'");


      //luaenv.AddLoader((ref string filename) =>
      //{
      //    if (filename == "fishHotFix")
      //    {
      //      string path = @"C:\Users\User\Desktop\XLua\fishHotFix.lua.txt";
      //      return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
      //    }
      //    return null;
      //});
      //luaenv.DoString("require 'fishHotFix'");

      luaenv.AddLoader(MyLoader);//加载.lua文件
      luaenv.DoString("require 'fishHotFix'");//执行HotFix.lua
    }

    private byte[] MyLoader(ref string filePath)
    {
      //string path = @"C:\Users\User\Desktop\XLua\" + filePath + ".lua.txt";
      string path = Application.streamingAssetsPath + "/fishhotfix/" + filePath + ".lua.txt";
      return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
    }

    void Update()
    {
      if (luaenv != null)
      {
            luaenv.Tick();
      }
    }

    void OnDestroy()
    {
      //luaenv Dispose之前注销
      //HotFixDispose.lua,注销lua执行方法
      luaenv.DoString("require 'fishHotFixDispose'");
      luaenv.Dispose();
    }
}4、自动识别文件配置、lua调用C#、C#调用lua(放到Assets\XLua\Editor目录下)
using System.Collections.Generic;
using System;
using XLua;
using System.Reflection;
using System.Linq;
using UnityEngine;

public static class HotFixConfig
{
    //筛选过的文件具有热更功能==类名添加
   
    public static List<Type> by_property
    {
      // X:\lemongame\slgrpg_2d\3d\slgrogue\Assets\ProjectTemplate\Plugins\Sirenix\Assemblies\Sirenix.OdinInspector.Editor.dll
      get
      {
            return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
                  where type.Namespace == null || !type.Namespace.StartsWith("XLua")
                  select type).ToList();//文件筛选
      }
    }

    //lua中要使用到C#库的配置,比如C#标准库,或者Unity API,第三方库等。
   
    public static List<Type> LuaCallCSharp = new List<Type>() {
                typeof(System.Object),
                typeof(UnityEngine.Object),
                typeof(Vector2),
                typeof(Vector3),
                typeof(Vector4),
                typeof(Quaternion),
                typeof(Color),
                typeof(Ray),
                typeof(Bounds),
                typeof(Ray2D),
                typeof(Time),
                typeof(GameObject),
                typeof(Component),
                typeof(Behaviour),
                typeof(Transform),
                typeof(Resources),
                typeof(TextAsset),
                typeof(Keyframe),
                typeof(AnimationCurve),
                typeof(AnimationClip),
                typeof(MonoBehaviour),
                typeof(ParticleSystem),
                typeof(SkinnedMeshRenderer),
                typeof(Renderer),
                typeof(WWW),
                //typeof(Light),
                typeof(Mathf),
                typeof(System.Collections.Generic.List<int>),
                typeof(Action<string>),
                typeof(UnityEngine.Debug)
            };

    //C#静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface
   
    public static List<Type> CSharpCallLua = new List<Type>() {
                typeof(Action),
                typeof(Func<double, double, double>),
                typeof(Action<string>),
                typeof(Action<double>),
                typeof(UnityEngine.Events.UnityAction),
                typeof(System.Collections.IEnumerator)
            };

    //黑名单
   
    public static List<List<string>> BlackList = new List<List<string>>(){
                new List<string>(){"System.Xml.XmlNodeList", "ItemOf"},
                new List<string>(){"UnityEngine.WWW", "movie"},
    #if UNITY_WEBGL
                new List<string>(){"UnityEngine.WWW", "threadPriority"},
    #endif
                new List<string>(){"UnityEngine.Texture2D", "alphaIsTransparency"},
                new List<string>(){"UnityEngine.Security", "GetChainOfTrustValue"},
                new List<string>(){"UnityEngine.CanvasRenderer", "onRequestRebuild"},
                //new List<string>(){"UnityEngine.Light", "areaSize"},
                //new List<string>(){"UnityEngine.Light", "lightmapBakeType"},
                //new List<string>(){"UnityEngine.Light", "shadowAngle"},
                //new List<string>(){"UnityEngine.Light", "shadowRadius"},
                //new List<string>(){"UnityEngine.Light", "SetLightDirty"},
                new List<string>(){"UnityEngine.WWW", "MovieTexture"},
                new List<string>(){"UnityEngine.WWW", "GetMovieTexture"},
                new List<string>(){"UnityEngine.AnimatorOverrideController", "PerformOverrideClipListCleanup"},
    #if !UNITY_WEBPLAYER
                new List<string>(){"UnityEngine.Application", "ExternalEval"},
    #endif
                new List<string>(){"UnityEngine.GameObject", "networkView"}, //4.6.2 not support
                new List<string>(){"UnityEngine.Component", "networkView"},//4.6.2 not support
                new List<string>(){"System.IO.FileInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
                new List<string>(){"System.IO.FileInfo", "SetAccessControl", "System.Security.AccessControl.FileSecurity"},
                new List<string>(){"System.IO.DirectoryInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
                new List<string>(){"System.IO.DirectoryInfo", "SetAccessControl", "System.Security.AccessControl.DirectorySecurity"},
                new List<string>(){"System.IO.DirectoryInfo", "CreateSubdirectory", "System.String", "System.Security.AccessControl.DirectorySecurity"},
                new List<string>(){"System.IO.DirectoryInfo", "Create", "System.Security.AccessControl.DirectorySecurity"},
                new List<string>(){"UnityEngine.MonoBehaviour", "runInEditMode"},
            };


#if UNITY_2018_1_OR_NEWER
   
    public static Func<MemberInfo, bool> MethodFilter = (memberInfo) =>
    {
      if (memberInfo.DeclaringType.IsGenericType && memberInfo.DeclaringType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
      {
            if (memberInfo.MemberType == MemberTypes.Constructor)
            {
                ConstructorInfo constructorInfo = memberInfo as ConstructorInfo;
                var parameterInfos = constructorInfo.GetParameters();
                if (parameterInfos.Length > 0)
                {
                  if (typeof(System.Collections.IEnumerable).IsAssignableFrom(parameterInfos.ParameterType))
                  {
                        return true;
                  }
                }
            }
            else if (memberInfo.MemberType == MemberTypes.Method)
            {
                var methodInfo = memberInfo as MethodInfo;
                if (methodInfo.Name == "TryAdd" || methodInfo.Name == "Remove" && methodInfo.GetParameters().Length == 2)
                {
                  return true;
                }
            }
      }
      return false;
    };
#endif
}5、Asset/StreamingAssets的lua文件(测试lua是否执行修改原有C#逻辑,可以按具体项目来编写)
(1)fishHotFix.lua.txt
local util = require '../../XLua/Resources/xlua/util'

--1、执行新的逻辑
xlua.hotfix(CS.FUIWindow_CoverUIVO, 'FTest', function(self)
        CS.UnityEngine.Debug.Log("hotfix .. FTest .. by .. streamingAssetsPath .. lua")
end)


--2、执行原来的逻辑
util.hotfix_ex(CS.FUIWindow_CoverUIVO, 'FTest1', function(self)
        self:FTest1()
        CS.UnityEngine.Debug.Log("hotfix .. FUIWindow_CoverUIVO .. FTest .. 1")
end)


--3、执行协程
xlua.hotfix(CS.FUIWindow_CoverUIVO, 'FIEnumTest', function(self)
        return util.cs_generator(function()
                print('hotfix .. FIEnumTest .. start')
                coroutine.yield(CS.UnityEngine.WaitForSeconds(3))
                print('hotfix .. FIEnumTest .. 3f')
        end)
end)


--4、修改界面控件逻辑
xlua.hotfix(CS.FUIWindow_CoverUIVO, 'SetLoginType', function(self, login)
        print('hotfix .. SetLoginType .. login =', login, not login)
        self._fui.m_btn_login.visible = login
    self._fui.m_progressbar.visible = not login
        self._fui.m_text.visible = not login
        print('hotfix .. SetLoginType ..')
end)


--5、修改界面逻辑(注意添加CS,调用属性和方法)
util.hotfix_ex(CS.FUIWindow_MainTopUIVO, 'UpdateCurrency', function(self, notif)
        self:UpdateCurrency(notif)
        self._fui.m_Com_gold.m_title.text = 100
end)


--6、同级目录下lua逻辑
require 'fishHotFixPrint' (2)fishHotFixPrint.lua.txt
local util = require '../../XLua/Resources/xlua/util'

--修改(可以覆盖之前的)
util.hotfix_ex(CS.FUIWindow_MainTopUIVO, 'UpdateCurrency', function(self, notif)
        self:UpdateCurrency(notif)
        self._fui.m_Com_gold.m_title.text = 100
        self._fui.m_Com_diamond.m_title.text = CS.UserInfo.Instance:GetCurrency(CS.CurrencyType.diamond) + 100
end) (3)fishHotFixDispose.lua.txt
--在LuaEnv Dispose之前注销
xlua.hotfix(CS.FUIWindow_CoverUIVO,'FTest',nil)
xlua.hotfix(CS.FUIWindow_CoverUIVO,'FTest1',nil)
xlua.hotfix(CS.FUIWindow_CoverUIVO,'FIEnumTest',nil)
xlua.hotfix(CS.FUIWindow_CoverUIVO,'SetLoginType',nil)
xlua.hotfix(CS.FUIWindow_MainTopUIVO,'UpdateCurrency',nil)6、Lua和C#的连接(不修改HotFixConfig配置文件不需要执行1、2步)
(1)清除C#和lua链接文件;
(2)生成链接的中间文件;
(3)注入(Unity启动游戏时,注入成功弹窗)



注入成功提示



7、使用
页: [1]
查看完整版本: XLua 热更新方案