Unity资源热更-Addressables总结(三)

最近不赶项目了,我打算抽点时间继续写一些Unity的总结,因此我想先把Addressables总结完,前面两篇文章大致讲解了Addressables热更新的一个操作流程,相信大家已经知道怎么去使用Addressables了,这篇文章主要是做补充,如果以后有变更还会继续更新。

1.这里先说个大小包的问题,大概可以这么归类一下,即有些项目可能给渠道审核的是一个完整包,将全部资源包含在包体内,俗称大包,有些项目给的是一个尽可能小的包体,采用登录时下载资源的策略,俗称小包,小包模式可以直接用Addressables的Remote模式即可,像大包模式都是将资源打入包体,那么怎么给包体内的本地资源做热更新呢?

回到Addressables总结(一)的第7点,我提到过使用Cannot Change Post Release,具体是怎么操作的呢?

这里以Prefabs的Group举例,将你Addressables里所有的Group全部改成上图设置,这样打出来的AB包就会被打入包体内,需要注意的是在设置界面,我们仍然使用的是Remote地址,因为我们后续还是要继续做资源热更的:

 接下来我们随便修改一个或者N个Group里的资源,然后执行操作 Tools->Check for Content Update Restrictions,可以看到它会生成一个新的Group,如下图(这里我直接拿之前的图作为示意):

 这是Addressables默认给我们生成的,不过这样会有一些问题,每次我们有新的热更资源了,它不会使用这个已生成的Group,反而又生成了一个新的Group,我们知道大包模式,是会将所有资源打入包体,然而新生成的Group默认是Remote不是Local地址,之后再使用大包模式的话无法打入包体,除非你一个个去修改...另外还有一个致命的问题,如果你热更的资源很多,怎么把这些资源归类到之前的Group里又是个很麻烦的事情,为此我这边优化了大包热更新生成Group的问题,以下是代码:

    public static void CheckAddressablesLocalAndUpdate()
    {
        updateContents = new Dictionary<string, HashSet<AddressableAssetEntry>>();
        var path = ContentUpdateScript.GetContentStateDataPath(true);
        if (string.IsNullOrEmpty(path))
            Debug.LogWarning("No path specified for Content State Data file.");
        else if (!File.Exists(path))
            Debug.LogWarningFormat("No Content State Data file exists at path: {0}");
        else
        {
            var settings = AddressableAssetSettingsDefaultObject.Settings;
            var modifiedEntries = ContentUpdateScript.GatherModifiedEntriesWithDependencies(settings, path);
            foreach (var k in modifiedEntries.Keys)
            {
                Debug.Log("modified key:" + k.address+" and parentGroup:"+ k.parentGroup.Name);
                if (!updateContents.ContainsKey(k.parentGroup.Name))
                    updateContents[k.parentGroup.Name] = new HashSet<AddressableAssetEntry>();
                updateContents[k.parentGroup.Name].Add(k);
                foreach (var child in modifiedEntries[k])
                    updateContents[k.parentGroup.Name].Add(child);               
            }

            foreach (var groupName in updateContents.Keys)
            {
                var newGroupName = "HotUpdate" + groupName;
                var group = settings.FindGroup(newGroupName);
                if (group == null)
                {
                    group = settings.CreateGroup(newGroupName, false, false, true, null);
                    var schema = group.AddSchema<BundledAssetGroupSchema>();
                    schema.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteBuildPath);
                    schema.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteLoadPath);
                    schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackSeparately;
                    schema.AssetBundledCacheClearBehavior = BundledAssetGroupSchema.CacheClearBehavior.ClearWhenWhenNewVersionLoaded;
                    schema.UseUnityWebRequestForLocalBundles = true;
                    schema.RetryCount = 5;
                    group.AddSchema<ContentUpdateGroupSchema>().StaticContent = false;
                }
                Debug.Log("from:" + groupName + " move to:" + group.Name);
                settings.MoveEntries(updateContents[groupName].ToList(), group);
            }

            //ContentUpdateScript.BuildContentUpdate(settings, path);
        }
    }

简单来说就是我这边根据资源的改变,将它原来所在的Group的名字前面加了个HotUpdate前缀作为新的Group的名字,最后我注释了自动打AB包的代码,我个人觉得确认一下之后再手动操作打AB包比较保险一点,这样操作之后打包出来的大概会变成下图这样:

 这样是不是清晰很多了呢?然后如果我们项目进行到下一版本,又要重新打大包拿去审核的话,就可以一键将资源挪回原位然后重新打AB包不就行了吗?挪回去的代码比较简单,我这里就不贴了,这样就基本解决了大包模式的问题。

2.资源冗余的问题,关于资源依赖的问题,我想大家可能多多少少都有些了解,在这里我就不多做赘述了,总之我们在使用AB包的时候肯定会有部分资源重复打包的问题,造成整个AB包的总量偏大。我这边主要讲的还是解决办法,先打开Tools里的Analyze资源分析工具,可以看到有四条Rules:

扫描二维码关注公众号,回复: 15859984 查看本文章

 <1> Check Duplicate Bundle Dependencies:检查AB包里重复依赖的资源,这个最开始做资源优化的时候最有用,可以明显看到很多重复依赖的资源,然后自己对资源再去做规化

<2> Check Resources to Addressable Duplicate Dependencies:检查AB包和Resources文件夹里的资源是否存在重复依赖

<3> Check Scene to Addressable Duplicate Dependencies:检查AB包和Unity编辑器场景列表里的场景是否存在重复依赖

<4> Bundle Layout Preview:AB包的本体和依赖项

我估计项目常用的办法就是对每个资源都分别打包,因为简单省事可以最大化去冗余,不过这样也会或多或少存在些问题:1.散资源太多影响下载速度,2.太多AB包的元数据开销将占用大量的内存, 3.AB包数量超过一定值(最好不要超过4W个)很可能会在部分安卓机上闪退

由此可见控制AB包的数量也是很有必要的,如果项目资源不是很多可以分开打包,如果很多的话可能就需要自己再对资源做规化了,要想达到极致的内存优化效果,就得想办法组合打包,这样会稍微麻烦一点,但是效果也是立竿见影的。

 这里有篇Unity官方讲解的文章,大家有兴趣可以看看,估计能够加深你的理解:内存又双叒叕告急?你需要这份 Addressables 系统内存节省指南 - 哔哩哔哩

猜你喜欢

转载自blog.csdn.net/qq_33805569/article/details/131280946