一、分组(网上教程一大堆)
二、构建
构建前设置:
1、分组设置。所有组做远端构建加载选择,RemoteBuildPath 。RemoteLoadPath
2、AddressableAssetSettings设置
3、构建
三、导出信息分析:
1、Assets同级目录下,ServerData内,包含所有所需文件。
2、对应平台下。catalog.hash和catalog.json为版本检测和资源记录文件。其他为AB包。
3、Assets/AddressableAssetsData/Android下为热更记录文件,打热更包所需。
四、打热更包:
选择上述三、3的文件。更新后ServerData下catalog和修改的AB发生变化。
五、地址重定向:
Addressables.ResourceManager.InternalIdTransformFunc = LoadFunc;
public static bool CustomNet { get; private set; }public static string VersionURL;public static string AddressURL;private static string OldUrl = "http://localhost/";/// <summary>/// 设置热更地址/// </summary>/// <param name="_versionUrl">版本地址</param>/// <param name="_addressUrl">资源地址</param>public static void SetCustomAddress(string _versionUrl, string _addressUrl){CustomNet = true;VersionURL = _versionUrl;AddressURL = _addressUrl;
#if UNITY_EDITORUnityEngine.Debug.Log("设置版本地址:" + VersionURL);UnityEngine.Debug.Log("设置资源地址地址:" + AddressURL);
#endifAddressables.ResourceManager.InternalIdTransformFunc = LoadFunc;}private static string LoadFunc(IResourceLocation location){if (location.ResourceType == typeof(IAssetBundleResource) && location.InternalId.StartsWith("http")){string abAddress = location.InternalId.Replace(OldUrl, AddressURL);return abAddress; }return location.InternalId;}
六、热更,创建服务器,把ServerData/Android放上去。即可热更。
1、热更下载的catalog文件在 Application.persistentDataPath
2、下载的AB资源在 :C:\Users\Administrator\AppData\LocalLow\Unity
七、热更检测代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.Networking;public class Updater : MonoBehaviour
{public enum HotState{None,Version,Hash,Json,Download,StopDownload,}private HotState m_HotState = HotState.None;[SerializeField]public bool Hot = true;//多平台版本检测 -> 地址 [SerializeField]public string VersionURL = "CDN地址";[SerializeField]public string Catalog = "catalog";// 拉取CDN地址错误public System.Action<string> FirstAddressError;// 拉取hash版本地址错误public System.Action<string> VerionCheckError;// 拉取json版本地址错误public System.Action<string> VerionUpdateError;// 得到下载大小回调public System.Action<long> ResourceSize;// 下载进度回调public System.Action<float> DowonloadPercent;// 断网回调public System.Action DisconnectNet;// 重新联网回调public System.Action ReconnectNet;public static Updater Instance;private readonly List<object> _updateKeys = new List<object>();private IEnumerator IDownLoad;private NetworkReachability LastNet;private void Awake(){LastNet = Application.internetReachability;Instance = this;
#if UNITY_EDITORif (!Hot) // 动态设置分组模式{}
#endif}private void Start(){if (!Hot)EnterGame();elseStartCoroutine(SetAddress());}private IEnumerator SetAddress(){m_HotState = HotState.Version;if (Application.internetReachability == NetworkReachability.NotReachable){DisconnectNet?.Invoke();yield break;}UnityWebRequest request = UnityWebRequest.Post(VersionURL, "");yield return request.SendWebRequest();if (request.isHttpError || request.error != null){FirstAddressError?.Invoke(request.error);Debug.LogError("配置地址出错:" + request.error);yield break;}else{string datas = request.downloadHandler.text;CDNAddress CDN = JsonUtility.FromJson<CDNAddress>(datas);string url = CDN.GetGetAddressURL();Debug.Log("CDN :" + url);url = "http://192.168.11.51:8089/";AddressablesExt.SetCustomAddress(url + Catalog + ".hash", url);}StartCoroutine(DoUpdateAddressadble());}IEnumerator DoUpdateAddressadble(){m_HotState = HotState.Hash;if (Application.internetReachability == NetworkReachability.NotReachable){DisconnectNet?.Invoke();yield break;}AsyncOperationHandle<IResourceLocator> initHandle = Addressables.InitializeAsync();yield return initHandle;//检测更新AsyncOperationHandle<List<string>> checkHandle = Addressables.CheckForCatalogUpdates(false);yield return checkHandle;if (checkHandle.Status != AsyncOperationStatus.Succeeded){VerionCheckError?.Invoke(checkHandle.OperationException.ToString());Debug.LogError("版本检测失败:" + checkHandle.OperationException.ToString());yield break;}if (checkHandle.Result.Count > 0){m_HotState = HotState.Json;AsyncOperationHandle<List<IResourceLocator>> updateHandle = Addressables.UpdateCatalogs(checkHandle.Result, false);yield return updateHandle;if (updateHandle.Status != AsyncOperationStatus.Succeeded){Debug.LogError("版本更新失败:" + updateHandle.OperationException.ToString());VerionUpdateError?.Invoke(updateHandle.OperationException.ToString());yield break;}// 更新列表迭代器List<IResourceLocator> locators = updateHandle.Result;foreach (var locator in locators){_updateKeys.AddRange(locator.Keys);// key 里一堆乱七八糟的东西 }Addressables.Release(checkHandle);Addressables.Release(updateHandle);}else //版本已经更新过的,采用这种方式{IEnumerable<IResourceLocator> locators = Addressables.ResourceLocators;foreach (var locator in locators){_updateKeys.AddRange(locator.Keys);// key 里一堆乱七八糟的东西 }}AsyncOperationHandle<long> sizeHandle = Addressables.GetDownloadSizeAsync(_updateKeys as IEnumerable<object>);yield return sizeHandle;Debug.Log("热更资源总大小:" + NetFormat.GetDisplaySize(sizeHandle.Result));if (sizeHandle.Result > 0){ResourceSize?.Invoke(sizeHandle.Result);StartDownLoad();}else{Debug.Log("没有检测到更新 - 无需下载");EnterGame();}Addressables.Release(sizeHandle);}public void StartDownLoad(){IDownLoad = DownLoad();StartCoroutine(IDownLoad);}private void StopDownLoad(){m_HotState = HotState.StopDownload;StopCoroutine(IDownLoad);}private void Update(){if (Application.internetReachability != LastNet){switch (Application.internetReachability){case NetworkReachability.NotReachable:if (m_HotState == HotState.Download){StopDownLoad();}DisconnectNet?.Invoke();Debug.LogError("网络链接未打开");break;case NetworkReachability.ReachableViaCarrierDataNetwork:case NetworkReachability.ReachableViaLocalAreaNetwork:ReconnectNet?.Invoke();TryAgin();Debug.Log("流量 OR WIFI");break;default:break;}LastNet = Application.internetReachability;}}public void TryAgin(){Debug.Log(m_HotState);switch (m_HotState){case HotState.None:break;case HotState.Version:StartCoroutine(SetAddress());break;case HotState.Hash:case HotState.Json:StartCoroutine(DoUpdateAddressadble());break;case HotState.Download:StartDownLoad();break;case HotState.StopDownload:StartDownLoad();break;default:break;}}public HotState GetHotState(){return m_HotState;}public void Quit(){Application.Quit();}
#if UNITY_EDITOR[UnityEditor.MenuItem("AATool/PrintState")]private static void PrnitState(){Debug.LogError(Instance.m_HotState);}
#endifprivate IEnumerator DownLoad(){m_HotState = HotState.Download;if (Application.internetReachability == NetworkReachability.NotReachable){DisconnectNet?.Invoke();yield break;}AsyncOperationHandle downHandle = Addressables.DownloadDependenciesAsync(_updateKeys as IEnumerable<object>, Addressables.MergeMode.Union, false);while (!downHandle.IsDone){float _bar = downHandle.GetDownloadStatus().Percent;DowonloadPercent?.Invoke(downHandle.GetDownloadStatus().Percent);UnityEngine.Debug.Log(_bar);yield return null;}yield return downHandle;if (downHandle.Status != AsyncOperationStatus.Succeeded){Debug.LogError("下载失败 - 重新尝试下载");StartDownLoad();Addressables.Release(downHandle);yield break;}else{Addressables.Release(downHandle);// 进入游戏EnterGame();}}// 进入游戏void EnterGame(){// TODODebug.Log("进入游戏");RootTools.MainScript.GetOrAddComponent<GameRoot>();Object.Destroy(gameObject);}private void OnApplicationQuit(){}private void OnApplicationFocus(bool focus){}
}