赞
踩
因为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的使用已经完毕,下一章会演示同时更新资源与代码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。