美文网首页Unity干货
Addressables 初始化流程与热更

Addressables 初始化流程与热更

作者: 阿飞咯 | 来源:发表于2020-10-14 23:56 被阅读0次

    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。

    相关文章

      网友评论

        本文标题:Addressables 初始化流程与热更

        本文链接:https://www.haomeiwen.com/subject/jqvgpktx.html