您现在的位置是:首页 >学无止境 >Unity 热更新基础HybridCLR:Windows平台使用(HybridCLR手记二)网站首页学无止境

Unity 热更新基础HybridCLR:Windows平台使用(HybridCLR手记二)

作孽就得先起床 2023-06-28 09:19:01
简介Unity 热更新基础HybridCLR:Windows平台使用(HybridCLR手记二)

项目是根据官网的示例工程进行修改的,版本参数如下:

unity:2021.2.20

wolong:v2.1.0

il2cpp_plus:v2021_2.1.0

-------------------------------------------------------------

1、安装:参考:第一篇文章Unity 热更新基础HybridCLR:安装部署(HybridCLR手记二)_作孽就得先起床的博客-CSDN博客

2、引入示例工程:

请访问官方的文件仓库:github或者是gitee,这里提供的是它gitee的示例工程网址:

hybridclr_trial: HybridCLR的示例项目 (gitee.com)

下载它

完成后导入项目:

导入到你项目同工程目录下,导入内容为:(图片为下载的示例工程),箭头为导入项目

(1提示的是目录)

步骤1(共2步)

 然后还有

步骤2(共2步)

 这里导进去了一个流文件读取插件,为了保证稳定因为官方用的是通过这个流文件插件读取的方案,但是热更流文件目录是只读目录,为了符合规范,因此依然选择了WWW方案,后面会对他进行修改,这里先导入进去

这样示例工程就导入完成了,进入项目

再次检查这几个选项是否一致:

 

 

 1、这里简单说下是咋回事。简单来说这是选择的热更新程序集,我们更新的就是他。

我这里写的是因为我的脚本是属于这个程序集(如图)

 当然,您也可以自己直接建程序集来进行热更新,如果您要自己建使用上面的就好了,就是这个

 直接拖拽上去就好了,如果手动输入的请去掉后缀

然后来到这重新安装下:

 

 这俩重新走下根据平台我这里是Win64,Generate->ALL

场景选择:main

Generate->ALL:是最容易报错的阶段,官方也有文档,写的也很详尽了,一般我们只需要找个地方先出个包就好了(不管出包是否成功,这里主要是为了Generate),出包一定要选择:

不要使用代码来进行此操作 

然后:出.dll包文件

这时候我们点击运行就好了,示例工程就此完成

但要热更,故此需要调整一些东西来满足热更需要:

1、在工程目录中新建一个文件夹,创建一个代码,这个文件夹下的代码将是我们要热更的脚本代码(大概会是这样)

 (因为wolong是通过.dll文件来进行热更新的)

2、项目工程中找到代码:LoadDll

接下来要对他进行修改:里面修改后代码如下:(注释版由ChatGPT提供)

请关注下目录,并在相应的文件下创建好目录进行使用

using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;

public class LoadDll : MonoBehaviour
{
    
   static  List<string> aotMetaAssemblyFiles = new List<string>()
    {
        "mscorlib.dll",
        "System.dll",
        "System.Core.dll",
    };

   private List<string> aotFiles = new List<string>();
   private List<string> aotFil= new List<string>();

   private Dictionary<string, WWW> _dic = new Dictionary<string, WWW>();

    void Start()
    {
        // 使用BetterStreamingAssets插件,即使在Android平台也可以直接读取StreamingAssets下内容,简化演示。
     //   BetterStreamingAssets.Initialize();
        
   
        Loadwww();
        
        StartGame();
    }

    void Loadwww()
    {
        foreach (var aotDllName in aotMetaAssemblyFiles)
        {
            aotFiles.Add(aotDllName);
        }

        aotFiles.Add("Assembly-CSharp.dll");
        aotFiles.Add("Main.dll");
        
        foreach (var item in aotFiles)
        {
            if (item.EndsWith(".dll"))
            {
                string str = item + ".bytes";
                aotFil.Add(str);
            }
        }
        
        aotFil.Add("prefabs");
        
        foreach (var item in aotFil)
        {
            string dllBytes =Application.persistentDataPath + ("/HotUpdate/HotDllFix/" + item);
            
            WWW www = new WWW("file://"+dllBytes);
            if (www.error!=null)
            {
                
            }
           
            _dic.Add(item,www);
        }
        
    }
    


    void StartGame()
    {
        LoadMetadataForAOTAssemblies();

#if !UNITY_EDITOR
// //Assembly-CSharp.dll.bytes
        System.Reflection.Assembly.Load(_dic["Assembly-CSharp.dll.bytes"].bytes);
#endif
//prefabs
        AssetBundle prefabAb = AssetBundle.LoadFromMemory(_dic["prefabs"].bytes);
        GameObject testPrefab = Instantiate(prefabAb.LoadAsset<GameObject>("HotUpdatePrefab.prefab"));
    }


    
    
    

    /// <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 aotMetaAssemblyFiles)
        {
            byte[] dllBytes =
                File.ReadAllBytes(Application.persistentDataPath + ("/HotUpdate/HotDllFix/" + aotDllName + ".bytes"));
            // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
            LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
            Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
        }
    }
}

//注释版(人工智障他是真的,最后还要自己来)

using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;

public class LoadDll : MonoBehaviour
{
    //wolong需要的执行dll文件
   static  List<string> aotMetaAssemblyFiles = new List<string>()
    {
        "mscorlib.dll",
        "System.dll",
        "System.Core.dll",
    };

   private List<string> aotFiles = new List<string>();
   private List<string> aotFil= new List<string>();

   private Dictionary<string, WWW> _dic = new Dictionary<string, WWW>();

    void Start()
    {
        // 使用BetterStreamingAssets插件,即使在Android平台也可以直接读取StreamingAssets下内容,简化演示。
     //   BetterStreamingAssets.Initialize();
        
   
        Loadwww();
        
        StartGame();
    }

    void Loadwww()
    {
        foreach (var aotDllName in aotMetaAssemblyFiles)
        {
            aotFiles.Add(aotDllName);
        }
        //加入新的.dll库,分别是要跟新的dll,和官方启动项目的dll
        aotFiles.Add("Assembly-CSharp.dll");
        aotFiles.Add("Main.dll");
        //加后缀方便更新
        foreach (var item in aotFiles)
        {
            if (item.EndsWith(".dll"))
            {
                string str = item + ".bytes";
                aotFil.Add(str);
            }
        }
        //加入预制体
        //因为有些用的是预制体上挂载的方式进行的热更
        aotFil.Add("prefabs");
        //设置www加载项目录
        foreach (var item in aotFil)
        {
            string dllBytes =Application.persistentDataPath + ("/HotUpdate/HotDllFix/" + item);
            
            WWW www = new WWW("file://"+dllBytes);
            if (www.error!=null)
            {
                
            }
           //添加进集合准备加载
            _dic.Add(item,www);
        }
        
    }
    


    void StartGame()
    {
        //启动官方的文件,具体参见官方文档
        LoadMetadataForAOTAssemblies();
//依据平台进行运行
#if !UNITY_EDITOR
// 
       //通过www进行加载(具体可参见官方文档)
        System.Reflection.Assembly.Load(_dic["Assembly-CSharp.dll.bytes"].bytes);
#endif
        //通过www进行加载(具体可参见官方文档)
        AssetBundle prefabAb = AssetBundle.LoadFromMemory(_dic["prefabs"].bytes);
        GameObject testPrefab = Instantiate(prefabAb.LoadAsset<GameObject>("HotUpdatePrefab.prefab"));
    }


    
    
    

    /// <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 aotMetaAssemblyFiles)
        {
            //修改了加载的文件目录,原来这里加载的是流文件目录下的东西,这里改到了p目录
            byte[] dllBytes =
                File.ReadAllBytes(Application.persistentDataPath + ("/HotUpdate/HotDllFix/" + aotDllName + ".bytes"));
            // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
            LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
            Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
        }
    }
}

提示:我这里的代码在出更新脚本文件后需要您手动从流目录下移动一下文件到加载的指定目录下,才能够正常运行,具体请自行分析下代码

在修改完代码后请重新执行这三步操作:

热更新wolong模块结束

 这文章都没VIP或收费,给点赞、收藏和关注吧~(嘤嘤~)

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。