一、分组(网上教程一大堆)
二、构建
构建前设置:
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_EDITOR
UnityEngine.Debug.Log("设置版本地址:" + VersionURL);
UnityEngine.Debug.Log("设置资源地址地址:" + AddressURL);
#endif
Addressables.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_EDITOR
if (!Hot) // 动态设置分组模式
{
}
#endif
}
private void Start()
{
if (!Hot)
EnterGame();
else
StartCoroutine(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);
}
#endif
private 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()
{
// TODO
Debug.Log("进入游戏");
RootTools.MainScript.GetOrAddComponent<GameRoot>();
Object.Destroy(gameObject);
}
private void OnApplicationQuit()
{
}
private void OnApplicationFocus(bool focus)
{
}
}