本篇会比较乱,边写边整理思路。
起因是用户说用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返回两个同样的位置。
文章评论