Unity 3D模型展示框架篇之Addressables+ILRuntime热更(完结篇)
Posted yxlalm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 3D模型展示框架篇之Addressables+ILRuntime热更(完结篇)相关的知识,希望对你有一定的参考价值。
系列文章目录
Unity 3D模型展示框架篇之项目整理
Unity 3D模型展示框架篇之框架运用
Unity 3D模型展示框架篇之自由观察(Cinemachine)
Unity 3D模型展示框架篇之资源打包、加载、热更(Addressable Asset System | 简称AA)
Unity 3D模型展示框架篇之资源打包、加载、热更(二)
Unity 3D模型展示框架篇之ILRuntime快速入门
Unity 3D模型展示框架篇之ILRuntime整合与应用
文章目录
前言
本项目将整合之前Unity程序基础小框架专栏在Unity3D模型展示项目基础上进行整合,并记录了集成过程中对原脚本的调整过程。增加了Asset Bundle+ILRuntime热更新技术流程。
本文章主要介绍如何在Unity工程中使用Addressable与ILRuntime项目进行整合的过程与使用实例。
一、热更新为什么要Addressables+ILRuntime?
ILRuntime
项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如ios)能够实现代码
的热更新。
Addressables
是官方推出的可寻址资产系统提供了一种通过"地址"加载资产的简单方法。它通过简化内容包的创建和部署来处理资产管理开销。可寻址资产系统使用异步加载来支持从任何位置加载任何依赖项集合。无论您使用直接引用、传统的资产包还是ResourceFolders进行资产管理,可寻址资产都提供了一种更简单的方法来使您的游戏更加动态。什么是资产?资产是您用来创建游戏或应用程序的内容。资产的常见例子包括预制、纹理、材料、音频剪辑和动画。什么是可寻址资产?将资产设置为“可寻址”允许您使用该资产的唯一地址在任何地方调用它。
简单来说ILRuntime
+Addressables
涵盖了热更新中的代码更新与资源热更新。
ILRuntime详见官方文档
Addressables官方文档
二、整合步骤
由于Addressables
不支持DLL资源打包,因此需要将DLL文件转化为二进制文件,再通过Addressables
进行打包进行资源热更后,加载时通过DLL文件流初始化ILRuntime
的入口应用程序域AppDomain
。完成对ILRuntime
代码工程的更新。
1.ILRuntime工程打包DLL转化为二进制文件
-
修改
ILRuntime
热更工程的DLL输出目录
修改目录的原因是因为StreamingAssets
在进行Addressables
分组时报错。因此创建Assets/ILRunTimeAndAddressable/AssetsPackage/HotFixDll
、Assets/ILRunTimeAndAddressable/AssetsPackage/HotFixDllToBytes
,HotFixDll
为生成DLL文件目录,HotFixDllToBytes
为DLL转化二进制文件的存放目录。
-
创建DLL转二进制文件编辑器
在Editor文件夹中创建DllToBytes.cs
DllToBytes.cs
代码如下:
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
public class DllToBytes
public static string normalPath = Application.dataPath + "/ILRunTimeAndAddressable/AssetsPackage/HotFixDll";
public static string normalPathToSave = Application.dataPath + "/ILRunTimeAndAddressable/AssetsPackage/HotFixDllToBytes";
[MenuItem("MyMenu/ILRuntime/DllToByte")]
public static void DllToByte()
DllToByte(true);
[MenuItem("MyMenu/ILRuntime/DllToByteChoose")]
public static void DllToByteChoose()
DllToByte(false);
private static void DllToByte(bool autoChoosePath)
string folderPath, savePath;
if (autoChoosePath)
folderPath = normalPath;
else
folderPath = EditorUtility.OpenFolderPanel("dll所在的文件夹", Application.dataPath + "/addressable/IlRuntime", string.Empty);
if (string.IsNullOrEmpty(folderPath))
return;
DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
FileInfo[] fileInfos = directoryInfo.GetFiles();
List<FileInfo> listDll = new List<FileInfo>();
List<FileInfo> listPdb = new List<FileInfo>();
for (int i = 0; i < fileInfos.Length; i++)
if (fileInfos[i].Extension == ".dll")
listDll.Add(fileInfos[i]);
else if (fileInfos[i].Extension == ".pdb")
listPdb.Add(fileInfos[i]);
if (listDll.Count + listPdb.Count <= 0)
Debug.Log("文件夹下没有dll文件");
else
Debug.Log("路径为:" + folderPath);
if (autoChoosePath)
savePath = normalPathToSave;
else
savePath = EditorUtility.OpenFolderPanel("dll要保存的文件夹", Application.dataPath + "/addressable/IlRuntime", string.Empty);
Debug.Log("-----开始转换dll文件------");
string path = string.Empty;
for (int i = 0; i < listDll.Count; i++)
//$ 符号的作用:等同于string.Format(),不用写占位符了,直接拼起来就可以了
path = $"savePath/Path.GetFileNameWithoutExtension(listDll[i].Name)_dll_res.bytes";
Debug.Log(path);
BytesToFile(path, FileToBytes(listDll[i]));
Debug.Log("------dll文件转换结束---------");
Debug.Log("-----开始转换pdb文件------");
for (int i = 0; i < listPdb.Count; i++)
//$ 符号的作用:等同于string.Format(),不用写占位符了,直接拼起来就可以了
path = $"savePath/Path.GetFileNameWithoutExtension(listPdb[i].Name)_pdb_res.bytes";
BytesToFile(path, FileToBytes(listPdb[i]));
Debug.Log("------pdb文件转换结束---------");
AssetDatabase.Refresh();
/// <summary>
/// file转byte
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
private static byte[] FileToBytes(FileInfo fileInfo)
return File.ReadAllBytes(fileInfo.FullName);
/// <summary>
/// byte转文件
/// </summary>
/// <param name="path"></param>
/// <param name="bytes"></param>
private static void BytesToFile(string path, byte[] bytes)
Debug.Log($"路径为:path\\nlength:bytes.Length");
File.WriteAllBytes(path, bytes);
2.Unity工程加载热更DLL二进制文件
HotFixMgr.cs
增加LoadHotFixAssembly
通过二进制文件加载热更DLL。修改之前加载DLL的路径Application.streamingAssetsPath
改为新改的路径。整体代码如下:
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class HotFixMgr : MonoBehaviour
public static HotFixMgr instance;
public ILRuntime.Runtime.Enviorment.AppDomain appdomain;
private System.IO.MemoryStream m_fs, m_p;
public static HotFixMgr Instance
get
if (instance==null)
instance=new GameObject("HotFixMgr").AddComponent<HotFixMgr>();
instance.LoadHotFixAssembly();
return instance;
// Start is called before the first frame update
void Start()
public void LoadHotFixAssembly()
dllPath = Application.dataPath + "/ILRunTimeAndAddressable/AssetsPackage/HotFixDll";
appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();
#if UNITY_android
WWW www = new WWW(Application.streamingAssetsPath + "/Hotfix.dll");
#else
WWW www = new WWW("file:///" + dllPath + "/HotFix_Project.dll");
#endif
while (!www.isDone)
//yield return null;
System.Threading.Thread.Sleep(100);
if (!string.IsNullOrEmpty(www.error))
Debug.LogError(www.error);
byte[] dll = www.bytes;
www.Dispose();
#if UNITY_ANDROID
www = new WWW(Application.streamingAssetsPath + "/Hotfix.pdb");
#else
www = new WWW("file:///" + dllPath + "/HotFix_Project.pdb");
#endif
while (!www.isDone)
//yield return null;
System.Threading.Thread.Sleep(100);
if (!string.IsNullOrEmpty(www.error))
Debug.LogError(www.error);
byte[] pdb = www.bytes;
System.IO.MemoryStream fs = new MemoryStream(dll);
System.IO.MemoryStream p = new MemoryStream(pdb);
appdomain.LoadAssembly(fs, p, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
OnILRuntimeInitialized();
/// <summary>
/// 加载dll,pdb
/// </summary>
/// <param name="dll"></param>
/// <param name="pdb"></param>
public void LoadHotFixAssembly(byte[] dll, byte[] pdb)
m_fs = new MemoryStream(dll);
m_p = new MemoryStream(pdb);
try
appdomain.LoadAssembly(m_fs, m_p, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
catch
Debug.LogError("加载热更DLL失败,请确保已经通过VS打开Assets/Samples/ILRuntime/1.6/Demo/HotFix_Project/HotFix_Project.sln编译过热更DLL");
return;
appdomain.DebugService.StartDebugService(56000);
OnILRuntimeInitialized();
void OnILRuntimeInitialized()
//appdomain.Invoke("Hotfix.Game", "Initialize", null, null);
#if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE)
//由于Unity的Profiler接口只允许在主线程使用,为了避免出异常,需要告诉ILRuntime主线程的线程ID才能正确将函数运行耗时报告给Profiler
appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
#endif
//下面再举一个这个Demo中没有用到,但是UGUI经常遇到的一个委托,例如UnityAction<float>
appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction>((action) =>
return new UnityEngine.Events.UnityAction(() =>
((System.Action)action)();
);
);
// Update is called once per frame
void Update()
修改ProLaunch.cs
增加对热更DLL的加载入口
具体代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
/// <summary>
/// 加载方式
/// </summary>
public enum LoadMode
ByLocalDll,
ByLocalAddressable
public class ProLaunch : MonoBehaviour
/// <summary>
/// 显示下载状态和进度
/// </summary>
public Text UpdateText;
public Text DownText;
public Button btnCheckAndUpdate;
public Button btnUpdate;
public Button btnDown;
public Button btnLogin;
public Slider Slider;//滑动条组件
private List<object> _updateKeys = new List<object>();
//public Transform father;
[Tooltip("dll文件的加载方式")]
public LoadMode loadingMode = LoadMode.ByLocalAddressable;
// Start is called before the first frame update
void Start()
//retryBtn.gameObject.SetActive(false);
btnCheckAndUpdate.onClick.AddListener(() =>
StartCoroutine(DoUpdateAddressadble());
);
btnUpdate.onClick.AddListener(() =>
UpdateCatalog();
);
// 默认自动执行一次更新检测
//StartCoroutine(DoUpdateAddressadble());
StartHotFix();
btnDown.onClick.AddListener(() =>
DownLoad();
);
btnLogin.onClick.AddListener(() =>
SceneManager.LoadScene(1);
//StartCoroutine(LoadScene("Test2"));
);
// Update is called once per frame
void Update()
/// <summary>
/// 加载dll
/// </summary>
/// <returns></returns>
public async System.Threading.Tasks.Task StartHotFix()
//去服务器上下载最新的aa包资源
//下载热更代码
//string m_url=null;
byte[] dll = new byte[] ;
byte[] pdb = new byte[] ;
if (loadingMode == LoadMode.ByLocalDll)
//StartCoroutine(CheckHotUpdate(dll,pdb));
HotFixMgr.instance.LoadHotFixAssembly();
else if (loadingMode == LoadMode.ByLocalAddressable)
TextAsset assetDll = await Addressables.LoadAssetAsync<TextAsset>("HotFix_Project_dll_res").Task;
dll = assetDll.bytes;
TextAsset assetPdb = await Addressables.LoadAssetAsync<TextAsset>("HotFix_Project_pdb_res").Task;
pdb = assetPdb.bytes;
HotFixMgr.instance.LoadHotFixAssembly(dll, pdb);
public async void UpdateCatalog()
//初始化Addressable
var init = Addressables.InitializeAsync();
await init.Task;
//开始连接服务器检查更新
var handle = Addressables.CheckForCatalogUpdates(false);
await handle.Task;
Debug.Log("check catalog status " + handle.Status);
if (handle.Status == AsyncOperationStatus.Succeeded)
List<string
参考技术A
现在游戏行业属于低迷期,短期内还看不到市场反弹的迹象,如果你注意过这几年的新闻,会发现15年后国家对游戏管控是越来越严格了,18年开始国内游戏审查,游戏审批都断了一阵子,直接导致半年多没有新游戏面市(这也是吃鸡手游一直没收费,现在直接改和平精英的原因),市场低迷到了现在。 很多中小公司是关门了的,而Unity开发商主力正是中小型公司。
如果坚持想入行游戏开发的话,建议找微信小游戏、网页游戏方向的,这个未来几年还有不错的市场。 如果不限制游戏,可以看看Web开发,网页、网站制作、微信小程序开发。这几个在三四年内会比游戏更吃香。
参考技术B
现在用这种开发工具开发游戏的还是比较多的,现在游戏开发的公司也不少,找到一份工作应该不难。只是看你的游戏开发水平到达什么程度,有时遇到一个好公司是非常重要的
参考技术C
.Unity3D是一款游戏引擎,你学习他找工作不难,难就难在看你准备付出多少,你现在大一,一直努力学习Unity3D,等你大三的时候,估计你应该能会不少,找个六千左右的工作应该没有问题,如果你在努力些八千到一万的都可以找到,但是你不要 ...
参考技术D
Unity前景如何?现在uny tv还能找到工作吗?就肯定是可以找到工作,他还是比较好的 这个肯定可以发展的,现在还可以找到工作,是不是比较闲用的?现在是前景一片光明的,是比较好找工作的
以上是关于Unity 3D模型展示框架篇之Addressables+ILRuntime热更(完结篇)的主要内容,如果未能解决你的问题,请参考以下文章
winform展示Unity3D文件(支持动态改变文件路径)