本项目工程是用2022.3.17f1c1,亲测可用,工程在附件链接里。
资源均来源于网络,仅供学习和参考使用,版权归原作者所有,勿作商业用途,请在下载后24小时之内自觉删除。
本站发布的内容若无意中侵犯到您的权益,请联系我们,本站将在看到后立即删除。
- 华佗热更aa包:在Unity中HybridCLR中,导入CLR5.2.0,包名:com.code-philosophy.hybridclr,链接:https://gitee.com/focus-creative-games/hybridclr_unity.git,在build中设置il2cpp,在HybridCLR中installer中安装对应版本,在setting中设置HotUpdate程序集,在Generate中点All生成所有,在CompileDll中ActiveBuildTarge激活,然后点击BuildTool复制dll到aa包中,导入Addressables,包名:com.unity.addressables,链接:github.com/Unity-Technologies/Addressables-Sample,在Addressables中设置Remote远端资源获取,开启Host中的服务,在Group中Build资源或者Update资源,那么资源将打在ServerData中,当生成exe后会从ServerData中读取更新资源,从而下载到沙盒缓存目录中。 Addressables资源加载时完成后释放资源句柄 应注释掉释放资源句柄,否则会导致材质丢失//Addressables.Release(handle);
复制代码- using HybridCLR;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Reflection;
- using UnityEngine;
- using UnityEngine.AddressableAssets;
- using UnityEngine.AddressableAssets.ResourceLocators;
- using UnityEngine.ResourceManagement.AsyncOperations;
- using UnityEngine.UI; // 使用UI命名空间
- public class CheckUpdateCtrl : MonoBehaviour
- {
- // 元数据文件列表,这些是AOT程序集的元数据文件
- private static readonly List<string> MetadataList = new List<string>()
- {
- "mscorlib.dll",
- "System.Core.dll",
- "System.dll",
- };
- [Serializable]
- private class DownloadInfo
- {
- public List<string> CatalogsInfo = new List<string>(); // 保存需要下载的目录信息
- }
- private DownloadInfo m_DownloadInfo = new DownloadInfo(); // 实例化一个DownloadInfo对象
- private List<object> DownloadCatalogsKey = new List<object>(); // 用于保存下载资源的Key列表
- private const string DOWNLOADKEY = "DOWNLOADKEY"; // 保存更新信息的PlayerPrefs键
- // 检查是否有目录更新
- private bool HasCatalogsUpdate => m_DownloadInfo.CatalogsInfo?.Count > 0;
- // 进度条相关
- public Slider progressBar; // 用于显示进度的滑动条
- public Text progressText; // 用于显示进度百分比的文本
- // MonoBehaviour的Start方法,在游戏开始时调用
- void Start()
- {
- DontDestroyOnLoad(this); // 保证该对象在场景切换时不被销毁
- StartCoroutine(Check()); // 启动更新检查的协程
- }
- private IEnumerator Check()
- {
- // 按顺序执行以下步骤
- yield return LoadMetadata(); // 加载元数据
- yield return CheckAssetUpdate(); // 检查资源更新
- yield return DownloadAsset(); // 下载更新的资源
- yield return LoadHotUpdateAssembly(); // 加载热更新的程序集
- yield return LoadCube(); // 生成Cube对象
- yield return LoadScene("EntryScene"); // 加载热更新的场景EntryScene
- yield return LoadScene("GameScene"); // 加载热更新的场景GameScene
- yield return LoadPlayer(); // 生成Player对象
- }
- private IEnumerator LoadMetadata()
- {
- foreach (var str in MetadataList)
- {
- // 异步加载元数据文件
- var handle = Addressables.LoadAssetAsync<TextAsset>(str);
- yield return handle;
- if (handle.Status == AsyncOperationStatus.Succeeded)
- {
- byte[] metadata = handle.Result.bytes; // 获取元数据字节数组
- // 加载元数据
- LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(metadata, HomologousImageMode.SuperSet);
- Debug.Log($"Loaded metadata for {str}, result: {err}");
- }
- else
- {
- Debug.LogError($"Failed to load metadata for {str}");
- }
- Addressables.Release(handle); // 释放资源句柄
- }
- }
- private IEnumerator CheckAssetUpdate()
- {
- var catalogsHandle = Addressables.CheckForCatalogUpdates(false); // 检查目录更新
- yield return catalogsHandle;
- if (catalogsHandle.Status == AsyncOperationStatus.Succeeded)
- {
- m_DownloadInfo.CatalogsInfo = catalogsHandle.Result; // 获取更新目录列表
- Addressables.Release(catalogsHandle); // 释放资源句柄
- if (HasCatalogsUpdate)
- {
- // 服务器有更新
- Debug.Log("Server has resource updates");
- string jsonStr = JsonUtility.ToJson(m_DownloadInfo);
- PlayerPrefs.SetString(DOWNLOADKEY, jsonStr); // 保存更新目录信息到本地
- }
- else if (PlayerPrefs.HasKey(DOWNLOADKEY))
- {
- // 本地有未完成的更新
- Debug.Log("Unfinished updates found in local storage");
- string savedStr = PlayerPrefs.GetString(DOWNLOADKEY);
- JsonUtility.FromJsonOverwrite(savedStr, m_DownloadInfo); // 读取本地保存的更新目录信息
- }
- if (HasCatalogsUpdate)
- {
- var locatorHandle = Addressables.UpdateCatalogs(m_DownloadInfo.CatalogsInfo, false); // 更新目录
- yield return locatorHandle;
- if (locatorHandle.Status == AsyncOperationStatus.Succeeded)
- {
- Debug.Log("Catalog update succeeded");
- List<IResourceLocator> resourceLocators = locatorHandle.Result; // 获取资源定位器列表
- Addressables.Release(locatorHandle); // 释放资源句柄
- DownloadCatalogsKey.Clear(); // 清空下载Key列表
- foreach (var locator in resourceLocators)
- {
- DownloadCatalogsKey.AddRange(locator.Keys); // 添加新的资源Key
- }
- }
- else
- {
- Debug.LogError("Catalog update failed");
- }
- }
- }
- else
- {
- Debug.LogError("Failed to check for catalog updates");
- }
- }
- private IEnumerator DownloadAsset()
- {
- // 等待一段时间来模拟资源加载速度
- yield return new WaitForSeconds(3.0f);
- var sizeHandle = Addressables.GetDownloadSizeAsync((IEnumerable)DownloadCatalogsKey); // 获取需要下载的资源大小
- yield return sizeHandle;
- if (sizeHandle.Status == AsyncOperationStatus.Succeeded)
- {
- long size = sizeHandle.Result; // 获取资源大小
- if (size == 0) yield break; // 如果没有需要下载的资源,则跳过
- Debug.Log("Downloading resources");
- var downloadHandle = Addressables.DownloadDependenciesAsync((IEnumerable)DownloadCatalogsKey, Addressables.MergeMode.Union, false); // 下载资源
- while (!downloadHandle.IsDone) // 在下载完成之前,更新进度条
- {
- float progress = downloadHandle.PercentComplete; // 获取下载进度
- UpdateProgressBar(progress); // 更新进度条
- yield return null;
- }
- if (downloadHandle.Status == AsyncOperationStatus.Succeeded)
- {
- PlayerPrefs.DeleteKey(DOWNLOADKEY); // 下载完成后删除本地保存的更新信息
- Debug.Log("Download completed");
- }
- else
- {
- Debug.LogError("Download failed");
- }
- Addressables.Release(downloadHandle); // 释放资源句柄
- }
- else
- {
- Debug.LogError("Failed to get download size");
- }
- Addressables.Release(sizeHandle); // 释放资源句柄
- }
- private void UpdateProgressBar(float progress)
- {
- if (progressBar != null)
- {
- progressBar.value = progress; // 更新进度条的值
- }
- if (progressText != null)
- {
- progressText.text = $"{progress * 100:F2}%"; // 更新进度百分比文本
- }
- }
- private IEnumerator LoadHotUpdateAssembly()
- {
- string label = "Assembly"; // 热更新程序集的标签
- var assembliesHandle = Addressables.LoadAssetsAsync<TextAsset>(label, null); // 加载热更新程序集
- yield return assembliesHandle;
- if (assembliesHandle.Status == AsyncOperationStatus.Succeeded)
- {
- foreach (var dll in assembliesHandle.Result)
- {
- Assembly.Load(dll.bytes); // 加载程序集
- Debug.Log($"Loaded hot update assembly: {dll.name}");
- }
- }
- else
- {
- Debug.LogError("Failed to load hot update assemblies");
- }
- Addressables.Release(assembliesHandle); // 释放资源句柄
- }
- private IEnumerator LoadScene(string sceneName)
- {
- yield return new WaitForSeconds(1); // 延迟1秒加载场景
- var handle = Addressables.LoadSceneAsync(sceneName); // 加载场景
- yield return handle;
- if (handle.Status == AsyncOperationStatus.Succeeded)
- {
- Debug.Log($"Scene {sceneName} loaded successfully");
- }
- else
- {
- Debug.LogError($"Failed to load scene {sceneName}");
- }
- }
- private IEnumerator LoadPlayer()
- {
- var handle = Addressables.LoadAssetAsync<GameObject>("Player"); // 加载Player对象
- yield return handle;
- if (handle.Status == AsyncOperationStatus.Succeeded)
- {
- Instantiate(handle.Result); // 实例化Player对象
- Debug.Log("Player instantiated successfully");
- }
- else
- {
- Debug.LogError("Failed to load player");
- }
- Addressables.Release(handle); // 释放资源句柄
- }
- private IEnumerator LoadCube()
- {
- yield return LoadAsset<GameObject>("Cube"); // 加载并实例化Cube对象
- yield return new WaitForSeconds(3.0f);
- }
- private IEnumerator LoadAsset<T>(string address) where T : UnityEngine.Object
- {
- // 等待一段时间来模拟资源加载速度
- yield return new WaitForSeconds(3.0f);
- // 异步开始加载资源
- AsyncOperationHandle<T> handle = Addressables.LoadAssetAsync<T>(address);
- // 在加载过程中更新进度条
- while (!handle.IsDone)
- {
- float progress = handle.PercentComplete;
- UpdateProgressBar(progress); // 更新进度条
- yield return null;
- }
- // 检查资源加载状态
- if (handle.Status == AsyncOperationStatus.Succeeded)
- {
- // 访问已加载的资源
- T loadedAsset = handle.Result;
- Debug.Log($"{typeof(T).Name} loaded successfully: {loadedAsset.name}");
- // 如果是 GameObject 类型的资源,则实例化它
- if (loadedAsset is GameObject)
- {
- Instantiate(loadedAsset as GameObject);
- }
- }
- else
- {
- Debug.LogError($"Failed to load asset at address: {address}");
- }
- // 完成后释放资源句柄 注释掉释放资源句柄,否则会导致材质丢失
- //Addressables.Release(handle);
- }
- private IEnumerator LoadAssetA<T>(string address) where T : UnityEngine.Object
- {
- var handle = Addressables.LoadAssetAsync<T>(address); // 加载指定地址的资源
- yield return handle;
- if (handle.Status == AsyncOperationStatus.Succeeded)
- {
- T loadedAsset = handle.Result; // 获取加载的资源
- Debug.Log($"{typeof(T).Name} loaded successfully: {loadedAsset.name}");
- if (loadedAsset is GameObject)
- {
- Instantiate(loadedAsset as GameObject); // 实例化GameObject类型的资源
- }
- }
- else
- {
- Debug.LogError($"Failed to load asset at address: {address}");
- }
- Addressables.Release(handle); // 释放资源句柄
- }
- // 存储资源句柄的列表
- private List<AsyncOperationHandle> activeHandles = new List<AsyncOperationHandle>();
- // 泛型方法,用于加载指定地址的资源并显示进度条
- private IEnumerator LoadAssetB<T>(string address) where T : UnityEngine.Object
- {
- // 异步开始加载资源
- AsyncOperationHandle<T> handle = Addressables.LoadAssetAsync<T>(address);
- activeHandles.Add(handle); // 将句柄添加到列表中
- // 在加载过程中更新进度条
- while (!handle.IsDone)
- {
- float progress = handle.PercentComplete;
- UpdateProgressBar(progress); // 更新进度条
- yield return null;
- }
- // 检查资源加载状态
- if (handle.Status == AsyncOperationStatus.Succeeded)
- {
- // 访问已加载的资源
- T loadedAsset = handle.Result;
- Debug.Log($"{typeof(T).Name} loaded successfully: {loadedAsset.name}");
- // 如果是 GameObject 类型的资源,则实例化它
- if (loadedAsset is GameObject)
- {
- Instantiate(loadedAsset as GameObject);
- }
- }
- else
- {
- Debug.LogError($"Failed to load asset at address: {address}");
- }
- }
- // 调用该方法以释放所有资源句柄
- public void ReleaseAllHandles()
- {
- foreach (var handle in activeHandles)
- {
- Addressables.Release(handle);
- }
- activeHandles.Clear();
- }
- }
复制代码
|