HybridCLR+Addressables资源代码全热更框架 二

Posted 枫尘。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HybridCLR+Addressables资源代码全热更框架 二相关的知识,希望对你有一定的参考价值。

第二章 使用huotuo 与 addressables

文章目录

一.修改HybridCLR打包方式

因为HybridCLR实例代码中使用的是传统AssetBundle打包方式,将预制体,程序集,场景打包到ab包中,在这里我们将替换为Addressables打包
1.创建热更程序集Hotfix

  • 新建文件夹HotFix

  • 新建文件HotFix.asmdef并检视界面修改属性如下

  • 新建文件App.cs
    App.cs代码如下

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;

namespace HotFix

    struct MyValue
    
        public int x;
        public float y;
        public string s;
    
    public class App
    
        public static int Main()
        
#if !UNITY_EDITOR
            LoadMetadataForAOTAssembly();
            Debug.Log("ydd-- AOT程序集加载完毕!");
#endif
            TestAOTGeneric();

            LoadScene();
            return 0;
        
        /// <summary>
        /// 测试 aot泛型
        /// </summary>
        public static void TestAOTGeneric()
        
            var arr = new List<MyValue>();
            arr.Add(new MyValue()  x = 1, y = 10, s = "abc" );
            Debug.Log("AOT泛型补充元数据机制测试正常");
        
        /// <summary>
        /// 切换场景
        /// </summary>
        static async void LoadScene()
        
            var handler = await Addressables.LoadSceneAsync("MainScene").Task;
            handler.ActivateAsync();
        

        /// <summary>
        /// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
        /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
        /// </summary>
        public static unsafe void LoadMetadataForAOTAssembly()
        
            // 可以加载任意aot assembly的对应的dll。但要求dll必须与unity build过程中生成的裁剪后的dll一致,而不能直接使用原始dll。
            // 我们在Huatuo_BuildProcessor_xxx里添加了处理代码,这些裁剪后的dll在打包时自动被复制到 项目目录/HuatuoData/AssembliesPostIl2CppStrip/Target 目录。

            /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
            /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误


            foreach (var dllBytes in LoadDll.aotDllBytes)
            
                fixed (byte* ptr = dllBytes.bytes)
                
                    // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
                    int err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly((IntPtr)ptr, dllBytes.bytes.Length);
                    Debug.Log($"LoadMetadataForAOTAssembly:dllBytes.name. ret:err");
                
            
        
    


  • 在检视界面修改Main/Main.asmdef文件,加入对Addressables的引用


2.打开LoadDll.cs,修改代码如下

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
#if !UNITY_EDITOR
using UnityEngine.AddressableAssets;
#endif

/// <summary>
/// 加载热更新Dll
/// </summary>
public class LoadDll : MonoBehaviour

    Assembly gameAss;
    public static TextAsset[] aotDllBytes;
    public static readonly List<string> aotDlls = new List<string>()
            
                "mscorlib.dll",
                "System.dll",
                "System.Core.dll",// 如果使用了Linq,需要这个
                // "Newtonsoft.Json.dll",
                // "protobuf-net.dll",
                // "Google.Protobuf.dll",
                // "MongoDB.Bson.dll",
                // "DOTween.Modules.dll",
                // "UniTask.dll",
            ;
    // Start is called before the first frame update
    void Start()
    
        LoadGameDll();
        RunMain();
    

    void LoadGameDll()
    
#if !UNITY_EDITOR
            aotDllBytes = new TextAsset[aotDlls.Count];
            for (int i = 0; i < aotDlls.Count; i++)
            
                aotDllBytes[i] = Addressables.LoadAssetAsync<TextAsset>(aotDlls[i]).WaitForCompletion();
            
            TextAsset hotfixDll = Addressables.LoadAssetAsync<TextAsset>("HotFix.dll").WaitForCompletion();
            gameAss = Assembly.Load(hotfixDll.bytes);
#else
        gameAss = AppDomain.CurrentDomain.GetAssemblies().First(assembly => assembly.GetName().Name == "HotFix");
#endif
    

    public void RunMain()
    
        if (gameAss == null)
        
            UnityEngine.Debug.LogError("dll未加载");
            return;
        
        var appType = gameAss.GetType("HotFix.App");
        var mainMethod = appType.GetMethod("Main");
        mainMethod.Invoke(null, null);

        // 如果是Update之类的函数,推荐先转成Delegate再调用,如
        //var updateMethod = appType.GetMethod("Update");
        //var updateDel = System.Delegate.CreateDelegate(typeof(Action<float>), null, updateMethod);
        //updateDel(deltaTime);
    

二.设置热更场景

使用上一章工程

1.修改默认场景名为Entry并加入BuildSetting作为热更新的入口,新建场景MainScene作为热更场景,然后打开Addressable Groups选择Create



2.在检视界面将MainScene标记为可寻址,名称为MainScene

3.打开Entry场景,修改界面UI如下,添加空对象挂载脚本LoadDll.cs

4.编译dll

5.首次打包获取aot dll(此次为无效打包,仅为获取aot dll),然后HybridCLRData/AssembliesPostIl2CppStrip/StandaloneWindows64目录会如下

6.复制4.5步中的HotFix.dll,mscorlib.dll,System.dll,System.Core.dll到Assets目录下
因为Addressables只能加载Assets目录下的资源,所以我们需要将HybridCLR生成的dll复制过去
Assets/Editor目录下编写编辑器脚本CopeDll2Assets.cs如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using HybridCLR;
using System.IO;

public class CopeDll2Assets : Editor

    [MenuItem("Tools/复制Dll到Assets/ActiveBuildTarget")]
    static void CopeByActive()
    
        Copy(EditorUserBuildSettings.activeBuildTarget);
    
    [MenuItem("Tools/复制Dll到Assets/Win32")]
    static void CopeByStandaloneWindows32()
    
        Copy(BuildTarget.StandaloneWindows);
    
    [MenuItem("Tools/复制Dll到Assets/Win64")]
    static void CopeByStandaloneWindows64()
    
        Copy(BuildTarget.StandaloneWindows64);
    

    [MenuItem("Tools/复制Dll到Assets/android")]
    static void CopeByAndroid()
    
        Copy(BuildTarget.Android);
    
    [MenuItem("Tools/复制Dll到Assets/ios")]
    static void CopeByIOS()
    
        Copy(BuildTarget.iOS);
    

    static void Copy(BuildTarget target)
    
        List<string> copyDlls = new List<string>()
        
            "HotFix.dll",
        ; 
        string outDir = BuildConfig.GetHotFixDllsOutputDirByTarget(target);
        string exportDir = Application.dataPath + "/Res/Dlls";
        if (!Directory.Exists(exportDir))
        
            Directory.CreateDirectory(exportDir);
        
        foreach (var copyDll in copyDlls)
        
            File.Copy($"outDir/copyDll", $"exportDir/copyDll.bytes", true);
        

        string aotDllDir = $"BuildConfig.AssembliesPostIl2CppStripDir/target";
        foreach (var dll in LoadDll.aotDlls)
        
            string dllPath = $"aotDllDir/dll";
            if (!File.Exists(dllPath))
            
                Debug.LogError($"ab中添加AOT补充元数据dll:dllPath 时发生错误,文件不存在。需要构建一次主包后才能生成裁剪后的AOT dll");
                continue;
            
            string dllBytesPath = $"exportDir/dll.bytes";
            File.Copy(dllPath, dllBytesPath, true);
        
        AssetDatabase.Refresh();
        Debug.Log("热更Dll复制成功!");
    

执行Tools/复制Dll到Assets/Win64,结构如下:

7.将4个文件均加入Addressables并修改名称

三.打包测试

1.打包Addressables Group Befault build Script

2.打PC包测试

直接进入热更场景,说明在热更工程App.Main中的Addressables加载场景与async/await语法糖也能正确使用

        /// <summary>
        /// 切换场景
        /// </summary>
        static async void LoadScene()
        
            var handler = await Addressables.LoadSceneAsync("MainScene").Task;
            handler.ActivateAsync();
        

总结

hybridclr与 addressables的使用已经完毕,下一章会演示同时更新资源与代码

Unity3D资源异步加载——Addressables资源异步加载

本篇介绍Addressables资源加载,也是基于AssetBundle之上分装,Addressables是在Unity2018版本以后出的,直接可以在Window-->Package Manager里找到Addressables,目前已经到了1.7.5版本。
技术图片

安装完成后,工程中的资源都会出现Addressable可选项
技术图片
安装完成后进入window->Asset Management->Addressable->Groups
技术图片

  1. 资源可以进行分组,进入后1处是默认的Group组
  2. Create->Group->Package Assets可以创建Group组
  3. Profile:设置自己资源打包的地址,并选择你设置的位置,进入到Manage Profile中可设置多个打包地址(可以是测试服,开发服,线上服,VIP服等等)本地/远端打包设置
    可以?生成许多不同的设置:测试服、正式服、VIP服等等
    ? Local Build Path - 本地端打包路路径
    ? Local Load Path - 本地端加载路路径
    ? Remote Build Path - 远端打包路路径
    ? Remote Load Path - 远端加载路路径技术图片
  4. Tool里面包括你所用到的工具技术图片包括资源加载分析Profiles,测试服务Hosting Services,Labels标签等等
  5. play Mode Script有三个选项,第一个是快速加载(faster),可以在Unity编辑器中测试,第二个是模拟加载(advanced),Unity模拟了一个远程加载的过程,第三个Build加载(requires),程序打包的时候,先要选择他,对资源进行打包技术图片
  6. Bulid就是打包资源

Addressables资源打包过程
技术图片

将需要异步加载的资源,勾选Addressable活着直接拖到你默认的Group组或者你自己创建的Group组中技术图片
标记1的位置可以修改你资源的名称
标记2的位置可以设置你资源的标签
注意:后续可以通过标签或者名字加载资源
将所有资源添加进来后,在Build的位置打包资源,资源打包基本就说完了,至于细节的东西,大家可以开API文档。

资源加载方式
上面资源打包完成后,进行资源异步加载

InstantiateAsync()
? 异步实例例化
? 系统不会等待
? 调?用完成时会回来接着运?行行 ? ?大量量实例例化不会卡住系统
LoadAssetAsync()
? 异步加载
? 资源可以在本地也可以在远端服务器

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Loading : MonoBehaviour
{
    //直接选择拖入目标
    public AssetReference box;

    /// <summary>
    /// 加载
    /// </summary>
    void LoadBox()
    {
        box.LoadAssetAsync<GameObject>().Completed += OnLoaded;
    }

    //加载完成的回调
    void OnLoaded(AsyncOperationHandle<GameObject> obj)
    {
        GameObject cube = obj.Result;
    }
}

通过名字加载技术图片

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Loading : MonoBehaviour
{

    /// <summary>
    /// 加载
    /// </summary>
    void LoadBox()
    {
        Addressables.LoadAssetAsync<GameObject>("cube").Completed += OnLoaded;

                //异步加载实例化
        //Addressables.InstantiateAsync("cube");
    }

    //加载完成的回调
    void OnLoaded(AsyncOperationHandle<GameObject> obj)
    {
        GameObject cube = obj.Result;
    }
}

通过标签名称加载(适合加载材质贴图等)
技术图片

  Addressables.LoadAssetsAsync<GameObject>(new List<object> { "key", "label" }, null, Addressables.MergeMode.Intersection).Completed += (AsyncOperationHandle<IList<GameObject>> obj) => {
            GameObject box = ((AsyncOperationHandle<IList<GameObject>>)obj).Result[0];
        };

注意:??
当?一个Resources?文件夹内的资源被标记为Addressable时,系统会?自 动将它从Resources?文件夹移出到Resources_moved的新?文件夹。
? 默认的关联位置会指向原来的旧路路径。
? 原本的加载代码会从Resources.LoadAsync <GameObject>(“map /
city.prefab”)变成 Addressables.LoadAssetAsync <GameObject>( “map / city.prefab”);

旧版版转换:
当?工程有Asset Bundles设置时,第?一次打开Addressables菜单会询问 是否要全部转入Addressables群组。

  • Addressables是基于Asset Bundles系统的延伸,你可以把Asset Bundles视为?手动管理理,Addressables视为?自动管理理。
  • 你是可以完全只采?用Addressables的。
  • 虽然说Addressables和Asset Bundles可以混?用,但官?方的?目标并非两
  • 者共存,?而是往Addressables能处理理?一切相关?工作为?目标。
  • public GameObject XXX 改为 public AssetReference XXX; ? Instantiate() 改为 AssetRefName.InstantiateAsync();
  • 加载?用LoadAssetAsync<GameObject>();

总结
旧版Assetbudle和Addressable相比,后者使用更简便,而且不用自己去管理资源存放的地址,资源更新也比较方便。
Addressables不是只有加载或是实例例化,你可以查询该物件在哪?里里。 ? 系统会帮你处理理关联性
Build Script可以让你?自?己写打包流程
Addressables是基于Asset Bundle架构做的?高阶流程。
未来也会以Addressable为主

Addressable目前也存在一些问题,比如不支持脚本打包、A工程打包,B工程加载使用存在Bug等等。

以上是关于HybridCLR+Addressables资源代码全热更框架 二的主要内容,如果未能解决你的问题,请参考以下文章

Unity资源热更-Addressables总结

Unity使用 Addressables 预加载所有资源,提现加载资源,发布webgl加载缓慢问题

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

游戏开发探究Unity Addressables资源管理方式用起来太爽了,资源打包加载热更变得如此轻松(Addressable Asset System | 简称AA)

Unity3d C# 实现AA包(Addressables)资源热更新的多个包异步加载并显示加载实时进度功能(含源码)