HybridCLR 热更新笔记 GF接入

这篇具有很好参考价值的文章主要介绍了HybridCLR 热更新笔记 GF接入。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

官方文档

实验环境

Unity 版本(国际版): Unity 2020.3.26.f1
hybridclr_unity : https://gitee.com/focus-creative-games/hybridclr_unity.git#v2.0.0-rc

安装HybridCLR (有gitee账号才可使用)

官方安装教程

添加 hybridclr_unity package

  • 方法一:
    在 Unity项目/Packages/manifest.json 文件中添加一行(注意逗号, 末尾行不需要在后面加逗号
    “com.focus-creative-games.hybridclr_unity”: “https://gitee.com/focus-creative-games/hybridclr_unity.git#v2.0.0-rc”,
    如:
{
  "dependencies": {
	"com.focus-creative-games.hybridclr_unity": "https://gitee.com/focus-creative-games/hybridclr_unity.git#v2.0.0-rc",
    "com.unity.2d.sprite": "1.0.0",
    "com.unity.2d.tilemap": "1.0.0",
    "com.unity.ide.rider": "3.0.7",
    "com.unity.ide.visualstudio": "2.0.12",
    "com.unity.render-pipelines.universal": "10.8.1",
    "com.unity.textmeshpro": "3.0.6",
    "com.unity.timeline": "1.6.2",
    "com.unity.ugui": "1.0.0",
    "com.unity.modules.ai": "1.0.0",
    "com.unity.modules.androidjni": "1.0.0",
    "com.unity.modules.animation": "1.0.0",
    "com.unity.modules.assetbundle": "1.0.0",
    "com.unity.modules.audio": "1.0.0",
    "com.unity.modules.cloth": "1.0.0",
    "com.unity.modules.director": "1.0.0",
    "com.unity.modules.imageconversion": "1.0.0",
    "com.unity.modules.imgui": "1.0.0",
    "com.unity.modules.particlesystem": "1.0.0",
    "com.unity.modules.physics": "1.0.0",
    "com.unity.modules.physics2d": "1.0.0",
    "com.unity.modules.screencapture": "1.0.0",
    "com.unity.modules.terrain": "1.0.0",
    "com.unity.modules.terrainphysics": "1.0.0",
    "com.unity.modules.tilemap": "1.0.0",
    "com.unity.modules.ui": "1.0.0",
    "com.unity.modules.uielements": "1.0.0",
    "com.unity.modules.umbra": "1.0.0",
    "com.unity.modules.unityanalytics": "1.0.0",
    "com.unity.modules.unitywebrequest": "1.0.0",
    "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
    "com.unity.modules.unitywebrequestaudio": "1.0.0",
    "com.unity.modules.unitywebrequesttexture": "1.0.0",
    "com.unity.modules.unitywebrequestwww": "1.0.0",
    "com.unity.modules.vehicles": "1.0.0",
    "com.unity.modules.video": "1.0.0",
    "com.unity.modules.wind": "1.0.0"
  }
}

  • 方法二:
    使用 git 拉取 https://gitee.com/focus-creative-games/hybridclr_unity.git 项目到本地
    创建文件夹 com.focus-creative-games.hybridclr_unity
    把拉取下来的文件拷贝到 com.focus-creative-games.hybridclr_unity 文件夹(不要拷贝 .git 文件夹)
    把 com.focus-creative-games.hybridclr_unity 文件夹 拷贝到 Unity项目/Packages/ 文件夹下

安装

运行 HybridCLR/Installer… 再点击安装 (有的版本比较特殊)

HybridCLR Unity项目设置

Build Setting 设置

  1. 使用 Faster runtime。(有的平台有,有的平台无此选项)

Player 设置

  1. Scripting Backend 必须是 IL2CPP
  2. Api Compatibility Level* 没特殊情况 设置为 .Net 4.x
  3. Use incremental GC 取消勾选,暂时不支持增量GC

HybridCLR Settings

  1. 热更新 dll(Hot Update Assemblies) 与 热更新 Assembly Definitions(Hot Update Assembly Definitions)
    不能把同一个dll 名字配置到 两个配置中。 两个都表示可以热更新的 dll 名称(不带扩展名)
    Hot Update Assembiles 表示普通dll
    Hot Update Assembly Definitions 表示Unity项目中的(assembly definition)程序集
  2. externalHotUpdateAssemblyDirs 外部热更新dll搜索路径
    如果热更新 dll 项目 是Unity外部的,则需要配置一个外部dll所在的路径。

泛型

1.HybridCLR的补充元数据技术。如果热更新 dll 中使用到 aot dll 中的泛型类,那么这个aot dll 就需要调用RuntimeApi.LoadMetadataForAOTAssembly 方法来补充元数据。
补充元数据有两个模式
HomologousImageMode.Consistent 只能使用裁减后的AOT dll
HomologousImageMode.SuperSet 既可以使用裁减后的AOT dll 也可以使用原始 AOT dll
补充元数据的泛型函数以解释方式运行,执行效率慢,最好提前在AOT中泛型实例化,(HybridCLR/Generate/AOTGenericReference)工具可以自动收集泛型实例
2.il2cpp 的泛型共享技术 (值类型无法使用,最好还是使用(第一种方法+AOT中编写一个泛型实例化))
详细介绍

我的理解

  1. AOT 表示表示静态编译。上下文中的 AOT dll 表示静态编译的 dll(可以理解为除了热更新dll,其他的就是 AOT dll)。静态编译一般是不能被更新的,HybridCLR 中也可以被热更新(需要使用DHE)
  2. 热更新 可以 依赖 热更新dll 以及 AOT dll, 但是 AOT 不可以依赖 热更新 dll。所以热更新dll一般采用 Assembly-CSharp 或者 外部 dll作为热更新 dll。
  3. 热更新多个 dll 时,需要先加载被依赖的 dll
  4. link.xml 中可以配置一些预留的 保留类。方便以后热更新dll 使用

接入实战

一个基于GameFrarmeWork(GF框架)的游戏框架

环境 Unity 2020.3.26f1

我之前是 2019.4.33f1 但是官方最低只支持 2019.4.40,如果要使用 2019.4.33f1 需要自己手动修改 il2cpp.dll。2019 与 2021 都需要额外处理一些东西,所以我选择了进行Unity升级。2020 版本不需要额外改动,是最简单接入的版本。
我做这个热更新只是为了打包方便,如果出现bug不想再用Unity Build项目。不做网络下载部分。

接入步骤
  1. 在Unity 项目的manifest中新增一行
    “com.focus-creative-games.hybridclr_unity”: “https://gitee.com/focus-creative-games/hybridclr_unity.git#v2.0.0-rc”,
  2. 点击 HybridCLR Installer -> 安装
  3. 修改相关配置
    关闭增量GC 取消 Use incremental GC 勾选
    配置热更新dlls 我选择热更新 Unity 主项目 Assembly-CSharp
  4. 新增游戏入口程序集,创建入口场景,编写入口场景
    HybridCLR 热更新笔记 GF接入
    HybridCLR 热更新笔记 GF接入
    Entry 脚本
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using HybridCLR;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

public class Entry : MonoBehaviour
{
    /// <summary>
    /// 这里填写需要补充元数据的 AOT dll
    /// </summary>
    public static List<string> AOTMetaAssemblyNames { get; } = new List<string>()
    {
        "mscorlib.dll",
        "System.dll",
        "System.Core.dll",
        
        //这里填写自己的ATO dll
        "FGUI.dll",
        "LightVelocityFrame.dll",
        "UnityGameFramework.Runtime.dll",
        "UnityEngine.dll",
        "GameFramework.dll",
        "Newtonsoft.Json.dll"
    };

    public const string MainHotFixDll = "Assembly-CSharp.dll";

    public static Assembly MainAssembly
    {
        get;
        private set;
    }

    //这里填写热更新 dll
    public static List<string> HotFixAssemblyNames { get; } = new List<string>()
    {
    };

    public static string DllDir => $"{Application.streamingAssetsPath}/HotFixDll";

    public static string GetDllPath(string asset)
    {
        return $"{DllDir}/{asset}";
    }

    /// <summary>
    /// 下载好的资源
    /// </summary>
    private static Dictionary<string, byte[]> s_assetDatas = new Dictionary<string, byte[]>();

    public static byte[] GetAssetData(string dllName)
    {
        return s_assetDatas[dllName];
    }
    
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(DownLoadAssets(this.StartGame));
    }

    private string GetWebRequestPath(string asset)
    {
        var path = GetDllPath(asset);
        if (!path.Contains("://"))
        {
            path = "file://" + path;
        }
        if (path.EndsWith(".dll"))
        {
            path += ".bytes";
        }
        return path;
    }

    public IEnumerator DownLoadAssets(Action onDownloadComplete)
    {
        var assets = new List<string>(){MainHotFixDll}.Concat(AOTMetaAssemblyNames).Concat(HotFixAssemblyNames);

        
        foreach (var asset in assets)
        {
            string dllPath = GetWebRequestPath(asset);
            UnityWebRequest www = UnityWebRequest.Get(dllPath);
            yield return www.SendWebRequest();
            
#if UNITY_2020_1_OR_NEWER
            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.Log(www.error);
            }
#else
            if (www.isHttpError || www.isNetworkError)
            {
                Debug.Log(www.error);
            }
#endif
            else
            {
                // Or retrieve results as binary data
                byte[] assetData = www.downloadHandler.data;
                Debug.Log($"dll:{asset}  size:{assetData.Length}");
                s_assetDatas[asset] = assetData;
            }
        }
        onDownloadComplete();
    }
    
    /// <summary>
    /// 启动游戏
    /// </summary>
    void StartGame()
    {
        LoadMetadataForAOTAssemblies();

        LoadHotFixDll();

        SceneManager.LoadScene("GameScene");
        
        //执行热更新入口代码 换成自己的
        var method = MainAssembly.GetType("LightVelocityFrame.GameEntry").GetMethod("Init");
        method.Invoke(null, null);
    }

    /// <summary>
    /// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
    /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
    /// </summary>
    private static void LoadMetadataForAOTAssemblies()
    {
        /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
        /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误
        /// 
        HomologousImageMode mode = HomologousImageMode.SuperSet;
        foreach (var aotDllName in AOTMetaAssemblyNames)
        {
            byte[] dllBytes = GetAssetData(aotDllName);
            // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
            LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
            Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
        }
    }

    private static void LoadHotFixDll()
    {
        MainAssembly = System.Reflection.Assembly.Load(GetAssetData(MainHotFixDll));
        
        foreach (var hotFixDllName in HotFixAssemblyNames)
        {
#if !UNITY_EDITOR
        System.Reflection.Assembly.Load(GetAssetData(hotFixDllName));
#endif
        }
    }
}


  1. 编写编辑器脚本 实现以下功能
    在 HybridCLRData\AssembliesPostIl2CppStrip\Android 文件夹中找出,热更新dll 中可能会继承的类所在的AOT程序集。放入到项目 StreamingAssets/HotFixDll目录中,并把后缀名改为 bytes
    在 HybridCLRData\HotUpdateDlls\Android 文件夹中找出,热更新 dll。放到项目StreamingAssets/HotFixDll目录中,并把后缀名改为 bytes
using System.Collections.Generic;
using System.IO;
using System.Linq;
using HybridCLR.Editor;
using HybridCLR.Editor.Commands;
using UnityEditor;
using UnityEngine;

namespace LightVelocityFrame.Editor
{
    public static class HybridCLRTool
    {
        private const string TitleGenerateAll = "【LVFrame.Builder】/HotUpdate_GenerateAll";

        private const string TitleCompileDll = "【LVFrame.Builder】/HotUpdate_Compile";
        
        [MenuItem(TitleGenerateAll)]
        public static void GenerateAndCopyDll()
        {
            PrebuildCommand.GenerateAll();
            CopyDll2StreamingAssets();
        }

        [MenuItem(TitleCompileDll)]
        public static void CompileDll()
        {
            CompileDllCommand.CompileDll(EditorUserBuildSettings.activeBuildTarget);
            CopyHotFixAssembilesToStreamingAssets();
        }

        private static void CopyDll2StreamingAssets()
        {
            CopyAOTAssembliesToStreamingAssets();
            CopyHotFixAssembilesToStreamingAssets();
        }

        private static void CopyAOTAssembliesToStreamingAssets()
        {
            var target = EditorUserBuildSettings.activeBuildTarget;
            string aotAssembliesSrcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
            string aotAssembliesDstDir = Entry.DllDir;
            
            foreach (var dll in Entry.AOTMetaAssemblyNames)
            {
                string srcDllPath = $"{aotAssembliesSrcDir}/{dll}";
                if (!File.Exists(srcDllPath))
                {
                    Debug.LogError($"没有找到 裁减后的 aot-dll {dll}, 请使用 Generate/all 命令生成 aot dll");
                    continue;
                }
                string dllBytesPath = $"{aotAssembliesDstDir}/{dll}.bytes";
                File.Copy(srcDllPath, dllBytesPath, true);
                Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}");
            }
        }

        private static void CopyHotFixAssembilesToStreamingAssets()
        {
            var target = EditorUserBuildSettings.activeBuildTarget;
            string hotAssembliesSrcDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
            string hotAssembliesDstDir = Entry.DllDir;
            
            var hotFixAssemblyNames = new List<string>(){Entry.MainHotFixDll}.Concat(Entry.HotFixAssemblyNames);
            foreach (var dll in hotFixAssemblyNames)
            {
                string srcDllPath = $"{hotAssembliesSrcDir}/{dll}";
                if (!File.Exists(srcDllPath))
                {
                    Debug.LogError($"没有找到热更新dll {dll}, 请使用 Generate/all 命令生成热更新dll");
                    continue;
                }
                string dllBytesPath = $"{hotAssembliesDstDir}/{dll}.bytes";
                File.Copy(srcDllPath, dllBytesPath, true);
                Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}");
            }
        }
    }
}
  1. 使用 HybridCLR/GenerateAndCopyDll 命令生成 并 拷贝 aot dll 以及 热更新 dll
    • 可能遇到的问题 Exception: resolve assembly: xxxx 失败! 如果是热更新dll找不到,请先运行HybridCLR/CompileDll/ActiveBuildTarget编译生成热更新dll。如果是AOT dll找不到,请先运行HybridCLR/Generate/LinkXml,接着在Build Settings中打包或者导出工程来生成AOT dll
      解决方案
      如果 xxxx 是 netstandard,那么是 Api Compatibility Level* 设置问题,需要改成 4.x
      如果 xxxx 是其他dll,这个问题很奇怪,解决方案在AOT dll 中找个地方使用 这个报错dll(定义字段,或者调用方案)。或者找到热更新代码中调用到这个dll的地方,尝试删除,不能删除就用前面这个方法。如果不行,重启再试。(我是这么解决的)。
  2. 构建 Android 项目
  3. 直接使用Android 构建 apk
遇到的问题

由于我的是老项目,不能直接使用 Andorid 构建好的项目。需要把Unity Build的项目与老项目进行融合,导致了一些错误。

  1. JNI DETECTED ERROR IN APPLICATION: JNI GetStaticMethodID called with pending exception java.lang.ClassNotFoundException: Didn’t find class “com.unity3d.player.PlayAssetDeliveryUnityWrapper”
    出现这个错误是 unity-classes.jar 这个文件没有同步,升级了Unity版本的原因。

  2. JNI FatalError called: Unable to load library:xxxxx [dlopen failed: library “libil2cpp.so” not found]
    build.gradle 中需要加入 BuildIL2Cpp 任务,参考Unity Build 的安卓项目

  3. 安卓 Build 报错 NDK is not installed
    在local.properties 中配置 ndk 目录
    HybridCLR 热更新笔记 GF接入

  4. Script Missing GF 使用HybridCLR 很可能会遇上这个错误
    错误原因:热更MonoBehaviour,如果是挂载在Prefab上,那么这个Prefab 需要是AssetBundle
    解决方法:参考
    使用AddComponent 添加 或者 把Prefab打包成AssetBundle
    GF 解决思路:
    GF 的基础组件作为 AOT 程序集,
    GF 的自定义组件使用 AddComponent 添加到游戏物体上

  5. 遇到 MissingMethodException xxx 错误
    错误原因:热更新中使用了其他程序集的泛型类,而没有把这个程序集作为AOT dll 添加注册元数据。
    解决方法:把这个Dll 配置到Entry.AOTMetaAssemblyNames 字段中
    调优,把这个泛型类 在 AOT dll中定义一次文章来源地址https://www.toymoban.com/news/detail-413115.html

到了这里,关于HybridCLR 热更新笔记 GF接入的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端常用的一些插件、UI框架、js库,样式库以及官方文档。【持续更新】

    1.1 文档地址 API文档 1.2 安装教程 1.下载安装 2.导入 2.1 文档地址 API文档 2.2 安装教程 1.下载安装 2.导入 3.1 文档地址 API文档 3.2 安装教程 1.下载安装 2.导入 3.安装遇到的问题 1)描述 ① 控制台报错 ② 终端报错 输出的内容都是 \\\"export xxx was not found in \\\'vue\\\' 2)解决 ① 先卸载 ya

    2024年02月03日
    浏览(42)
  • 学习笔记-elstaciElasticSearch7.17官方文档

    特征 适用于所有 Elasticsearch API 的强类型请求和响应。 所有 API 的阻塞和异步版本。 在创建复杂的嵌套结构时,使用流畅的构建器和功能模式允许编写简洁但可读的代码。 通过使用对象映射器(例如 Jackson 或任何 JSON-B 实现)无缝集成应用程序类。 将协议处理委托给一个 h

    2024年02月14日
    浏览(47)
  • GameFramework 框架详解之 如何接入热更框架HybridCLR

    HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的c#热更新方案 GameFramework是一个非常出色完整的基于Unity引擎的游戏框架,里面包含了非常多的模块,封装非常完整。 以前市面上的热更大多数都是Lua为主,后来出了一个ILRuntime的C#热更框架,虽然性能差了点,但

    2024年02月07日
    浏览(47)
  • Flink|《Flink 官方文档 - 部署 - 概览》学习笔记

    学习文档:《Flink 官方文档 - 部署 - 概览》 学习笔记如下: 上图展示了 Flink 集群的各个构建(building blocks)。通常来说: 客户端获取 Flink 应用程序代码,将其转换为 JobGraph,并提交给 JobManager JobManager 将工作分配给 TaskManager,并在那里执行实际的算子操作 在部署 Flink 时,

    2024年01月19日
    浏览(55)
  • Flink|《Flink 官方文档 - 内幕 - 文件系统》学习笔记

    学习文档:内幕 - 文件系统 学习笔记如下: Flink 通过 org.apache.flink.core.fs.FileSystem 实现了文件系统的抽象。这种抽象提供了一组通用的操作,以支持使用各类文件系统。 为了支持众多的文件系统, FileSystem 的可用操作集非常有限。例如,不支持对现有文件进行追加或修改。

    2024年02月03日
    浏览(38)
  • 机器人强化学习环境mujoco官方文档学习记录(一)——XML

    鉴于研究生课题需要,开始在mujoco中配置仿真环境。而官方文档中各种对象参数纷繁复杂,且涉及mujoco底层计算,不便于初学者进行开发设计。因此本文将MJCF模型的常用对象参数进行总结。 本文档仅供学习参考,如有问题欢迎大家学习交流。 本章是MuJoCo中使用的MJCF建模语言

    2024年02月02日
    浏览(57)
  • 【UGF】GameFramework接入HybridCLR(wolong)卧龙C#热更框架

    HybridCLR的推广已经做得相当好了,而且热更领域突然杀出一匹黑马,热度很高,不再多做介绍,可以点击进入HybridCLR开源地址了解详情。 在此之前用过tolua和xlua热更框架, 因为C#开发方式实在太爽,想支持热更又不想使用弱类型语言,于是对ILRuntime和HybridCLR进行了评估,了解

    2023年04月11日
    浏览(91)
  • ros2官方文档(基于humble版本)学习笔记

    由于市面上专门讲ROS 2开发的书籍不多,近期看完了《ROS机器人开发实践》其中大部分内容还是基于ROS 1写的,涉及topic,service,action等一些重要的概念,常用组件,建模与仿真,应用(机器视觉,机器语音,SLAM,机械臂),最后一章写了ROS 2的安装,话题通信和服务通信的示

    2024年02月11日
    浏览(42)
  • Spring MVC官方文档学习笔记(二)之DispatcherServlet

    1.DispatcherServlet入门 (1) Spring MVC是以前端控制器模式(即围绕着一个中央的Servelt, DispatcherServlet)进行设计的,这个DispatcherServlet为请求的处理提供了一个共用的算法,即它都会将实际的请求处理工作委托给那些可配置的组件进行执行,说白了,DispatcherServlet的作用就是进行统一调度,并

    2024年02月07日
    浏览(82)
  • ROS 2官方文档(基于humble版本)学习笔记(二)

    今天继续总结CLI 工具章的学习 理解节点(node) ROS 2图是一个ROS 2元件同时处理数据的网络,如果将它们全部映射并可视化它们,则包括所有可执行文件以及它们之间的连接。 ROS中的每个节点(node)都应该只为了单个的、模块化的目的而设计的,例如控制车轮电动机或从激光

    2024年02月10日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包