Addressables 初始化流程与热更

Addressables踩坑记录

首先应该了解ResourceManager的基本流程,核心主要是以下几块。

  • ResourceManager 资源管理类,目的是提供一种通用的方法来访问资源,同时抽象出特定的加载实现。
    • IResourceLocation 资源定位类,包含了加载资源的全部信息 (what/where/how/dependencies)
    • IResourceProvider 资源提供者,提供不同资源的加载解析方式
  • IAsyncOperation 异步操作类,通过ResourceManager.StartOperation调用向管理器里面注册异步操作,再由ResourcecManager进行统一调度管理(看上去贼蛋疼)。

下面走进Addressables.InitializeAsync(),探究Addressables 初始化流程。

  • InitializationOperation.CreateInitializationOperation
internal static AsyncOperationHandle<IResourceLocator> CreateInitializationOperation(AddressablesImpl aa, string playerSettingsLocation, string providerSuffix)
{
    var jp = new JsonAssetProvider();
    jp.IgnoreFailures = true; //!!!注意,这里坑得很
    aa.ResourceManager.ResourceProviders.Add(jp);
    var tdp = new TextDataProvider();
    tdp.IgnoreFailures = true;//!!!注意,这里坑得很
    aa.ResourceManager.ResourceProviders.Add(tdp);
    aa.ResourceManager.ResourceProviders.Add(new ContentCatalogProvider(aa.ResourceManager));
//以上是一些后面会用到解析catalog.json和catalog.hash对应Provider的初始化
    var runtimeDataLocation = new ResourceLocationBase("RuntimeData", playerSettingsLocation, typeof(JsonAssetProvider).FullName, typeof(ResourceManagerRuntimeData));

    var initOp = new InitializationOperation(aa);
    initOp.m_rtdOp = aa.ResourceManager.ProvideResource<ResourceManagerRuntimeData>(runtimeDataLocation);
    initOp.m_ProviderSuffix = providerSuffix;
    initOp.m_InitGroupOps = new InitalizationObjectsOperation();
    initOp.m_InitGroupOps.Init(initOp.m_rtdOp, aa);

    var groupOpHandle = aa.ResourceManager.StartOperation(initOp.m_InitGroupOps, initOp.m_rtdOp);

    return aa.ResourceManager.StartOperation<IResourceLocator>(initOp, groupOpHandle);
}

忽略前面provider初始化,经过理性分析,这里注册了三个异步操作,并且有依赖关系,分别为:initOp.m_rtdOp,initOp.m_InitGroupOps,以及initOp。

  • initOp.m_rtdOp 首先initOp.m_rtdOp是加载settings.json,包装在ProviderOperation,主要操作为异步调用m_Provider.Provide(new ProvideHandle(m_ResourceManager, this));provider的方法处理对应的资源,这里处理完成得到了setting.json数据,序列化到ResourceManagerRuntimeData数据结构对象里面,这里我们先打开一份setting.json
{
    "m_buildTarget": "StandaloneWindows64",
    "m_SettingsHash": "",
    "m_CatalogLocations": [{
        "m_Keys": ["AddressablesMainContentCatalogRemoteHash"],
        "m_InternalId": "http://localhost/StandaloneWindows64/catalog_2020.10.14.15.32.29.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.10.14.15.32.29.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_DisableCatalogUpdateOnStart": false,
    "m_IsLocalCatalogInBundle": false,
    "m_CertificateHandlerType": {
        "m_AssemblyName": "",
        "m_ClassName": ""
    },
    "m_AddressablesVersion": "1.16.1",
    "m_maxConcurrentWebRequests": 500
}
  • initOp.m_InitGroupOps,有了ResourceManagerRuntimeData数据之后执行InitalizationObjectsOperation异步操作,这里主要是初始化m_ExtraInitializationData(setting.json)内的数据(目前没用到)
  • 最后执行initOp,也就是InitializationOperation,初始化setting.json中的一些设置,初始化catalogLocations,从上面可以看到catalog有3个,如果没看Remote,也就只有一个,就没有接下来的步骤咯。
  • 初始化catalog,主要是包含三个:
    • 服务器上对于的catalog.hash
    • 本地持续化目录的catalog.hash
    • 对比本地与服务器上catalog的hash值,判断用本地的catalog.json还是远程的catalog.json,加载远程的catalog并替换本地的catalog,并解析出ContentCatalogData文件,具体json解析逻辑在ContentCatalogData.CreateCustomLocator中。
  • 最后解析出catalog.json中所有的资源location信息,并注册到ResourceManager中。
解读Addressables中的资源加载

Addressables中主要是通过本地和远端catalog.hash对比,并加载出最新的catalog.json文件,而catalog.json读取的location信息会指明你需要加载的资源在本地还是服务器,从而AssetBundleProvider中通过不同的加载方式进行加载,本地目录加载就不多说,远程加载使用了UnityWebRequestAssetBundle做加载,并搭配CachedAssetBundle做本地缓存,缓存使用BundleName以及资源的hash值,如果资源有变化,hash同样也会发生变化,本地命中失败,具体逻辑可参考AssetBundleProvider

关于Addressables中的热更

Addressables想依靠本地的catalog.hash与Remote的catalog.hash做对比,从而加载到我们打出的最新catalog.json文件,从而解析出资源的location,这里Addressables有一个bug,上文代码中标注了IgnoreFailures设置为了true,它的本意是做第一次加载本地缓存时,因为本地可持续目录是没有catalog文件的,所以忽略了加载失败的情况,但是这也会导致我们从Remote加载hash文件的时候,如果加载失败也并不会有异常抛出,而会直接使用可持续目录下的catalog.json。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 简介 Unity可寻址资源系统 可寻址资源系统提供了一种简单的方法通过“地址”加载资源。简化资源包的创建和部署的管...
    hh5460阅读 8,228评论 2 9
  • 基本信息 es6中const定义的属性是否可以改变? 可以的,为什么会这样呢?这是由于对象或者数组属于引用数据类。...
    习惯就好a阅读 8,457评论 0 1
  • 2019.3.38 比较两个文件 英文 detect: 检测2019.3.27 如何找到第一个bug出现的comm...
    饶家俊阅读 2,536评论 0 1
  • kettle源码分析 :本次源码分析 基于 kettle v4.0 分析: 背景:因最近新增一个需求,需要将原来在...
    唐僧吃肉_阅读 3,474评论 1 4
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,401评论 16 21