Unity Addressables热更流程

news2024/11/17 19:43:39

一、分组(网上教程一大堆)

二、构建

        构建前设置:

                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)
    {

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/592558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第十二届蓝桥杯国赛JavaB组题解

A. 整数范围 思路&#xff1a; 签到题。答案&#xff1a; 255 255 255 B. 纯质数 思路&#xff1a; 先用筛法筛出所有的质数&#xff0c;再根据题意判断&#xff0c;模板参考AcWing 数学知识。 代码&#xff1a; import java.io.BufferedReader; import java.io.IOExcepti…

Python相关环境变量配置和模拟手机app登录

【java环境变量配置】 接着&#xff0c;打开系统->高级系统设置->环境变量。新建一个JAVA_HOME C:\Program Files\Java\jdk1.8.0_201&#xff08;这里是你的安装路径&#xff0c;最好复制粘贴&#xff09; 然后在Path下添加 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 然后…

【LeetCode每日一题】——1493.删掉一个元素以后全为 1 的最长子数组

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 滑动窗口 二【题目难度】 中等 三【题目编号】 1493.删掉一个元素以后全为 1 的最长子数组 …

wx.request net::ERR_TOO_MANY_REDIRECTS

文章目录 问题解决方法一&#xff1a;请求头里添加Cookies方法二&#xff1a;使用weapp-cookie 问题 使用微信小程序开发者工具开发小程序项目时&#xff0c;wx.request 返回总是报 net::ERR_TOO_MANY_REDIRECTS wx.request发起一个get请求&#xff0c;一直重定向直到请求失败…

Java Web——Session实现购物车

实验名称&#xff1a; Session实现购物车 实验目的&#xff1a; &#xff08;1&#xff09;掌握什么是Cookie对象&#xff0c;掌握Cookie对象的使用 &#xff08;2&#xff09;掌握什么是Session对象&#xff0c;掌握Session对象的使用 &#xff08;3&#xff09;掌握使用…

弗雷歇distanceDTW(动态时间规整)算法(附部分代码)

1、理论知识 1.1 什么是弗雷歇距离&#xff0c;它是用来干什么的&#xff1f; 费雷歇distance是求两个序列匹配之后的最大距离&#xff0c;这里需要明确a&#xff09;两个序列&#xff1b;b&#xff09;匹配过程&#xff1b;c&#xff09;最大距离的含义。 a&#xff09;两个…

【java】 【Springboot】 开发通用审核流程服务模块

完全自研一个极其轻量级 通用审核流程服务 可以进行流程&#xff0c;节点配置&#xff0c;流程&#xff0c;节点审核人权限配置 批量审核&#xff0c;批量驳回&#xff0c;审核&#xff0c;驳回&#xff0c;批量退回第一步&#xff0c;退回第一步等操作 涉及数据库表单字段

OSPF最优路径选择

路由比较 1、内部区域>区域间路由>NSSA1>Nssa2 2、如果只有Ex1、Ex2或者Nssa1、nNssa2开销类型。则Ex1>Ex2或者Nssa1>Nssa2 3、如果Ex1、Nssa1,Ex2和Nssa2,Ex1和Nssa1优于Ex2和Nssa2 4、如果外部开销加上内部开销,Ex1和Nssa1一样,则Ex1和Nssa1相同负载分担 5、如果外…

CVE-2016-1000027安全漏洞分析和解决方案

文章目录 前言复现问题漏洞分析解决办法相关阅读 前言 CVE-2016-1000027 安全漏洞&#xff0c;该漏洞在5.x的最新版本(5.3.27)依然存在,官方未给出任何解决办法。在spring-web6.0之后&#xff0c;则不存在该漏洞。 受影响范围:spring-web<6.0 解决办法&#xff1a;升级到sp…

【机器学习】分类问题和Logistic回归算法详解

在阅读本文前&#xff0c;请确保你已经掌握代价函数、假设函数等常用机器学习术语&#xff0c;最好已经学习线性回归算法&#xff0c;前情提要可参考https://blog.csdn.net/weixin_45434953/article/details/130593910 分类问题是十分广泛的一个问题&#xff0c;其代表问题是&…

图表控件LightningChart JS v.4.1已经发布!引入虚线模式

LightningChart JS是性能最高的JavaScript图表库&#xff0c;专注于实时数据可视化。是Web上性能最高的图表库具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用&#xff0c;从而实现高刷新率和流畅的动画。…

固态硬盘基础知识:M.2 NVMe PCIe SATA的含义及区别

SATA接口 固态硬盘开始流行于笔记本电脑上&#xff0c;使用SATA接口&#xff0c;尺寸与笔记本硬盘相同&#xff0c;为2.5英寸。 那个时候&#xff0c;如果台式机需要加装固态硬盘&#xff0c;需要使用硬盘架&#xff0c;将固态硬盘安装在硬盘架上&#xff0c;然后再安装与机箱…

5.2.3 IP数据报(一)IP数据报的格式

5.2.3 IP数据报&#xff08;一&#xff09;IP数据报的格式 我们知道要想实现全球范围的通信除了地址要统一之外&#xff0c;数据格式也要统一&#xff0c;所以就有了IP分组&#xff0c;或者被称之为IP数据报&#xff0c;下面我们来学习IP分组的格式。如图 总体来说一个IP分组…

JetBrains的Java集成开发环境IntelliJ 2023版本在Linux系统的下载与安装配置教程

目录 前言一、IntelliJ安装二、使用配置总结 前言 IntelliJ IDEA Ultimate是一款功能强大的Java集成开发环境&#xff08;IDE&#xff09;。它提供了丰富的功能和工具&#xff0c;可以帮助开发人员更高效地编写、调试和部署Java应用程序。注&#xff1a;已在CentOS7.9和Ubuntu…

带大家来认识下SUMIF函数

如果您需要在Excel表格中对特定条件下的数据进行求和&#xff0c;那么SUMIF函数是一个非常有用的工具。SUMIF函数允许您在满足指定条件的情况下&#xff0c;将符合条件的单元格的值相加起来。在本文中&#xff0c;我们将向您介绍如何使用SUMIF函数来处理您的表格数据。 如下图…

想定制鞋子?先给脚部建模吧!

最近灌篮高手的电影正在火热上映中&#xff0c;湘北大战山王的比赛从漫画搬上了大荧幕&#xff0c;看得人热血沸腾&#xff0c;直呼“爷青回”&#xff0c;恨不得马上换上球衣球鞋&#xff0c;再去球场上挥汗如雨一番。 灌篮高手 同时NBA的季后赛也在如火如荼的进行中&#xf…

Cmake学习记录(九)--使用Cmake交叉编译Android .so库

文章目录 一、前言二、使用NDK进行编译的相关代码四、使用交叉工具链进行编译四、参考链接 一、前言 目前Android编译.so的话使用Android Studio比较简单&#xff0c;但是有时候时候Android Studio的话还需要创建一个Android的项目&#xff0c;这里记录下脱离Android Studio单…

华为OD机试真题B卷 Java 实现【百钱买百鸡问题】,附详细解题思路

一、题目描述 公元五世纪&#xff0c;我国古代数学家张丘建在《算经》一书中提出了“百鸡问题”&#xff1a;鸡翁一值钱五&#xff0c;鸡母一值钱三&#xff0c;鸡雏三值钱一。百钱买百鸡&#xff0c;问鸡翁、鸡母、鸡雏各几何&#xff1f; 现要求你打印出所有花一百元买一百…

2023-05-31-[音视频处理] FFmpeg使用指北1-视频解码

本文将详细介绍如何使用ffmpeg 4.4在C中解码多种格式的媒体文件&#xff0c;这些媒体文件可以是视频、视频流、图片&#xff0c;或是桌面截屏或USB摄像头的实时图片。解码文件后&#xff0c;还将每帧图片转换为OpenCV的Mat格式以供后续使用。 文章目录 1 基于ffmpeg的媒体文件解…

Java之旅(五)

运算符 算术运算符 加法&#xff08;&#xff09;减法&#xff08;-&#xff09;乘法&#xff08;*&#xff09;除法&#xff08;/&#xff09;取余&#xff08;%&#xff09;一元运算符 自增运算符&#xff08;&#xff09;自减运算符&#xff08;--&#xff09;变量前就先运…