安静如鸡

  • Home
  • About Me
  • Contact Me
  • 东京女子篮球活动记录
一个博客
  1. 首页
  2. Tech
  3. 正文

【Unity小贴士】关于Addressable的热更新

2023-09-29 0人点赞 0条评论

本篇会比较乱,边写边整理思路。

起因是用户说用LoadResourceLocationsAsync 一个Key获取到了两个同样的location,经查后,原因是在LoadResourceLocation之前调用了LoadContentCatalogAsync把远程的catalog导入,导致catalog重复了。(由于用户用的是Editor模式,不确定是否是本地的catalog和远程的重复还是单纯的导入远程catalog两次)

其实Unity关于热更新有一套方案,文档里面已经写的比较详细,但是文档里只写了要怎么做,没有写不可以怎么做(当然,哪个文档都不会这么写)所以用户可能误解了读取远程catalog需要用API手动读取。
https://docs.unity3d.com/Packages/com.unity.addressables@1.20/manual/RemoteContentDistribution.html

因为不太确定到底是怎么回事,查阅了很多内部外部资料,发现关于catalog说的都很模糊,但是文档里几乎是很明确的说,catalog的管理是自动管理的

By default, the Addressables system manages the catalog automatically at runtime. If you built your application with a remote catalog, the Addressables system automatically checks to see if you have uploaded a new catalog, and, if so, downloads the new version and loads it into memory.

那么问题来了,catalog到底是怎么自动从remote下载的?

首先assetbundle在打包的时候,本地会生成一个catalog和一个settings.json,在../Library/com.unity.addressables/aa/OSX/下面。这两个文件会跟着项目一起打包到app放在用户端里。下面是settings.json的主要内容,记录了hash位置,和本地catalog的位置。m_InternalId是在AddressableAssetSettings里设定的LoadPath

{
    "m_buildTarget": "StandaloneOSX",
    "m_SettingsHash": "",
    "m_CatalogLocations": [
        {
            "m_Keys": [
                "AddressablesMainContentCatalogRemoteHash"
            ],
            "m_InternalId": "http://192.168.12.8:59068/catalog_2020.05.03.19.43.34.hash",
            "m_Provider": "UnityEngine.ResourceManagement.ResourceProviders.TextDataProvider",
            "m_Dependencies": [],
            "m_ResourceType": {
                "m_AssemblyName": "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
                "m_ClassName": "System.String"
            }
        },
        {
            "m_Keys": [
                "AddressablesMainContentCatalogCacheHash"
            ],
            "m_InternalId": "{UnityEngine.Application.persistentDataPath}/com.unity.addressables/catalog_2020.05.03.19.43.34.hash",
            "m_Provider": "UnityEngine.ResourceManagement.ResourceProviders.TextDataProvider",
            "m_Dependencies": [],
            "m_ResourceType": {
                "m_AssemblyName": "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
                "m_ClassName": "System.String"
            }
        },
        {
            "m_Keys": [
                "AddressablesMainContentCatalog"
            ],
            "m_InternalId": "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/catalog.json",
            "m_Provider": "UnityEngine.AddressableAssets.ResourceProviders.ContentCatalogProvider",
            "m_Dependencies": [
                "AddressablesMainContentCatalogRemoteHash",
                "AddressablesMainContentCatalogCacheHash"
            ],
            "m_ResourceType": {
                "m_AssemblyName": "Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
                "m_ClassName": "UnityEngine.AddressableAssets.ResourceLocators.ContentCatalogData"
            }
        }
    ],
    "m_ProfileEvents": false,
    "m_LogResourceManagerExceptions": true,
    "m_ExtraInitializationData": [],
    "m_CertificateHandlerType": {
        "m_AssemblyName": "",
        "m_ClassName": ""
JSON

然后在Addressable第一次被使用到的时候,会进行初始化,在初始化的InitializationOperation里面,会读取settings.json在里面有本地catalog的位置和Remote的catalog hash的位置。

读取后,在InitializationOperation的Excute里面会执行LoadContentCatalog这里ContentCatalogProvider的Start会被叫到,然后在里面的DetermineIdToLoad函数会做一个hash的判断,比较本地的catalog的hash和remote的hash是否相同,如果不相同则直接从同样位置下载catalog.json文件。从而达到自动下载更新catalog的目的。

const string kCatalogExt =
#if ENABLE_BINARY_CATALOG
            ".bin";
#else
            ".json";
#endif

            internal string DetermineIdToLoad(IResourceLocation location, IList<object> dependencyObjects, bool disableCatalogUpdateOnStart = false)
            {
                //default to load actual local source catalog
                string idToLoad = GetTransformedInternalId(location);
                if (.......)
                {
                    var remoteHash = dependencyObjects[(int)DependencyHashIndex.Remote] as string;
                    m_LocalHashValue = dependencyObjects[(int)DependencyHashIndex.Cache] as string;
                    //...
                    if (string.IsNullOrEmpty(remoteHash) || disableCatalogUpdateOnStart) //offline
                    {

                    }
                    else //online
                    {
                        if (remoteHash == m_LocalHashValue && !m_Retried) //cache of remote is good and not forcing a retry state
                        {
                            idToLoad = GetTransformedInternalId(location.Dependencies[(int)DependencyHashIndex.Cache]).Replace(".hash", kCatalogExt);//kCatalogExt = .bin or .json
                        }
                        else //remote is different than cache, or no cache
                        {
                            idToLoad = GetTransformedInternalId(location.Dependencies[(int)DependencyHashIndex.Remote]).Replace(".hash", kCatalogExt);
                            m_RemoteHashValue = remoteHash;
                            ...
                        }
                    }
                }

                return idToLoad;
            }
C#

如果在这个自动操作后再用LoadResourceLocationsAsync读取同样的catalog,必然会造成一个key返回两个同样的位置。

标签: 暂无
最后更新:2024-02-01

Ellison

什么都懂点,什么都不精。属于混吃等死,享受生活,过一天算一天的享乐主义。喜欢电影,阅读,以及游戏和美食。

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2024 安静如鸡. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang