Unity Addressables 深入浅出(二)

本篇主要讲解使用Addressables系统做资源更新,基于Addressables1.8.5版本,下面简称AA系统


HostingService

这是AA系统自带的一个资源服务,我们可以指定一个目录存放远程资源,然后通过连接这个服务器,来更新资源.一般正式项目还是会自己去布置资源服务器,这个自带功能我们可以自己用来在开发时内部使用,毕竟配置很少,很便捷.

在这里插入图片描述
通过菜单栏可以打开这个工具,也可以在Group界面的Tools下拉列表中打开.
打开过后会看到下面的界面
在这里插入图片描述

可以通过这个窗口创建服务,Create中提供了两个选项在这里插入图片描述
这里只说Local Hosting,创建一个本地资源服务器,创建过后点击enable,这个服务器就启动了.
在这里插入图片描述
这个服务提供了3个变量,可以填在Profile中.现在我们可以不用管它了.当有服务请求时,会产生输出在Console中.


Group配置

首先创建4个Group,BuildPath决定了这个包被打包后存放的位置,LoadPath则是加载位置.每个包都可以存放在不同的位置.UpdateRestriction决定了这个包是静态还是非静态包

  • LocalStatic: 本地静态Group
    在这里插入图片描述

  • LocalNonStatic:本地非静态Group
    在这里插入图片描述

  • RemoteStatic:远程静态Group
    在这里插入图片描述

  • RemoteNonStatic: 远程非静态Group在这里插入图片描述

最后给每个Group里面添加一个预制件作为资源,然后打包验证一下更新流程.
在这里插入图片描述

这四个资源是包含一个文本的预制件,用文本表示自己是位于哪个Group中的,等打包过后,再修改预制件文本进行更新,看看是否有变化.
在这里插入图片描述


AddressableAssetSettings

除了上面的HostingServices和Group的配置,还需要对AddressableAssetSettings文件进行配置
在这里插入图片描述
主要是上面几个参数

  • Profile: 选择Profile,上一篇说过Profile中会配置有4个地址.
  • Disable Catalog Update On Startup: 勾选上,可以禁用自动更新catalog文件,勾选的目的是为了我们自己控制catalog的更新时机
  • Build Remote Catalog: 要通过AA系统更新资源,则必须勾选这个选项,在构建AB包的时候才会生成对应的catalog文件,来记录AB包的hash值和地址.
  • BuildPath: 这个变量只有在勾选Build Remote Catalog后才可以配置,这是catalog文件的生成目录.HostingService也是使用的这个目录.
  • LoadPath: 这个变量只有在勾选Build Remote Catalog后才可以配置,这是catalog文件的加载地址.发布应用程序过后,应用程序会通过这个地址来更新catalog文件.

打包

当这些都配置好了过后,开始打包测试.通过AA系统提供的默认打包脚本打包.
在这里插入图片描述
打包过后,可以看到远程资源都打包在了ServerData目录中,本地资源都打包在了Library/com.unity.addressables/StreamingAssetsCopy/aa/Android/中
在这里插入图片描述
在这里插入图片描述
同时在远程目录下会生成有catalog文件
在这里插入图片描述
.hash后缀的里面只包含一个hash值,是catalog文件的hash值,用于客户端检测catalog更新的时候会先对比这个hash值,才知道catalog文件有没有被修改,有修改才更新catalog文件.
.json文件就是catalog文件了,里面记录了每个AB包的hash值,地址,以及AB包里有哪些资源.客户端通过对比这些值,来检测是否有资源需要更新

而在Library/com.unity.addressables/StreamingAssetsCopy/aa/Android目录中还会生成一个catalog.json文件和settings.json文件以及link.xml
在这里插入图片描述
catalog.json文件与远程目录的catalog文件是一模一样的,我猜测这份文件是当没有开起远程更新的时候才会使用这份文件,开起远程更新过后,应该是使用的下载下来的catalog文件.
setting.json文件里面记录了catalog文件的远程更新地址,以及一些其它设置参数,实际上就是把工程中的AddressableAssetSettings文件转换成了json

还有一个十分重要的文件
在这里插入图片描述
这个后缀名为.bin的文件是记录所有AB包之间的依赖,以及分组情况的.相信之前自己做过AB资源管理的同学都知道.以前用BuildPiepline打AB包的时候都会生成Manifast文件来管理依赖,现在AA系统是用这个.bin文件来管理,Library/com.unity.addressables/StreamingAssetsCopy/Android目录下同样也会有一份一模一样的,用于在发布应用程序的时候一起打包进去.


测试加载

现在我发布一个安卓的apk文件,进行测试,看看AA系统到底是如何进行资源加载和更新的.

 public void LocalStatic()
    {
        Addressables.InstantiateAsync("Assets/Datas/local_static.prefab", parent);
    }

    public void LocalNonStatic()
    {
        Addressables.InstantiateAsync("Assets/Datas/local_non_static.prefab", parent);
    }

    public void RemoteStatic()
    {
        Addressables.InstantiateAsync("Assets/Datas/remote_static.prefab", parent);
    }

    public void RemoteNonStatic()
    {
        Addressables.InstantiateAsync("Assets/Datas/remote_non_static.prefab", parent);
    }

在这里插入图片描述
现在可以看到4个资源都正常的加载出来了,同时我的服务器上输出了3条请求
在这里插入图片描述
第一个是在AA系统初始化的时候请求的catalog的hash值,根据我的配置,我勾选了Disable Catalog Update On Startup,并且我的代码还没有调用更新catalog,所以不应该进行自动更新.这里只是请求了.hash文件,并没有真正的对catalog文件进行更新.

后面两个文件就是我们的远程静态AB包和非静态的AB包.程序加载的时候,会根据本地catalog文件(Library/com.unity.addressables/StreamingAssetsCopy/aa/Android目录中的那个和远程服务器目录中的catalog文件一模一样的文件)来查找资源,检测到两个本地资源的地址,都在本地,会直接进行加载,而两个远程资源本地没有,会到服务器上去下载,所以服务器会输出这两条log.

UnityEngine.Application.persistentDataPath/UnityCache/Shared
这是资源缓存的位置,我发现当我开始实例化那4个对象时,会在这4个目录中生成对应的缓存文件在这里插入图片描述
这里是资源缓存的位置,为什么会存在local的资源缓存呢,那是因为我之前对每个Group都勾选了Use Asset Bundle Cache,实际上这个选项对local的资源是没有用处的,反而会占用空间,所以对于local的Group应该把这个给取消掉.
在这里插入图片描述


更新

资源已经可以正常下载,加载.现在开始改动资源,然后再看看之前发布的那个apk上的资源是否可以正常进行更新.现在我在编辑器中对每个资源进行修改,改成下图那样
在这里插入图片描述
修改过后,我需要对资源进行重新打包,这时候需要做两个操作

  • Check for Content Update Restrictions

在这里插入图片描述
点击后会弹出对话框要求选择之前打包生成的.bin文件.然后会出现如下界面
在这里插入图片描述
然后点击apply changes,结果如下
在这里插入图片描述
首先可以看到local static 和remote static 的资源被移动到了一个名叫Content Update的Group中,这是工具自动生成的,是通过查询.bin文件,来找出相对于第一次打包被修改过的资源.但是发现一个问题,我明明对4个资源都进行了修改,但是这里只对static的资源进行了重新分配.
现在来详细说明一下静态Group和非静态Group.

  • 静态Group: 在发布后,无法被修改.就是说我客户端本地的这个Group中的AB包,都不能被修改了.所以只能通过这种增量更新的方式,另外创建一个Group,把修改后的资源放在这个新的Group中,然后重新打包AB,然后通过重写catalog文件,告诉客户端这个资源现在已经在这个新的Group中了,不要再去老的Group中加载了.但是老的资源依然还留在之前的那个AB包中.
  • 非静态Group: 在发布后,允许被修改.与静态Group相对,这个Group对应的AB包,是可以在后续进行覆盖更新的,相对于增量更新,整个AB包的覆盖更新可能会让未改动的资源也重新下载.

现在看来Check for Content Update Restrictions这个操作,其实就是找出相对于第一次发布后的静态Group的改动,然后重新生成一个Group.

  • Update a Previous Build
    在这里插入图片描述
    同样的,这个操作也需要选择之前的.bin文件,点击过后,会重新生成修改过的AB包,以及覆盖之前的catalog文件.
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    可以看到所有的非静态AB包都被覆盖了,而静态的AB包都没有被修改,因为静态包不允许被修改的,已经变为增量更新,生成了一个新的ab包,存放在了远程更新目录.
    在这里插入图片描述
    这个时候可以看到.json和.hash文件也被修改了.
    在这里插入图片描述
    在这里插入图片描述

测试更新

现在我们只打包了资源,并没有重新打包apk.我继续用之前的那个apk来测试.打开应用程序,分别点击下面4个加载按钮
在这里插入图片描述
可以看到当前的资源依然是之前的,这是因为我们还没有进行资源的更新,现在点击UpdateCatalog,执行如下代码,先更新catalog文件.

 public async void UpdateCatalog()
    {
        //开始连接服务器检查更新
        var handle = Addressables.CheckForCatalogUpdates(false);
        await handle.Task;
        Debug.Log("check catalog status " + handle.Status);
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            List<string> catalogs = handle.Result;
            if (catalogs != null && catalogs.Count > 0)
            {
                foreach (var catalog in catalogs)
                {
                    Debug.Log("catalog  " + catalog);
                }
                Debug.Log("download catalog start ");
                var updateHandle = Addressables.UpdateCatalogs(catalogs, false);
                await updateHandle.Task;
                foreach (var item in updateHandle.Result)
                {
                    Debug.Log("catalog result " + item.LocatorId);
                    foreach (var key in item.Keys)
                    {
                        Debug.Log("catalog key " + key);
                    }
                    _updateKeys.AddRange(item.Keys);
                }
                Debug.Log("download catalog finish " + updateHandle.Status);
            }
            else
            {
                Debug.Log("dont need update catalogs");
            }
        }
        Addressables.Release(handle);
    }

首先调用Addressables.CheckForCatalogUpdates(false),这一步是去向服务器请求.hash文件,检测catalog文件是否需要更新,这一步也是AA系统初始化会做的.返回的字符串列表如果数量大于0,那么就说明catalog文件需要更新,那么就调用Addressables.UpdateCatalogs(catalogs, false).这个时候可以看到服务器的输出,访问了这两个文件,现在客户端本地的catalog文件已经到最新了
在这里插入图片描述
再点击DownLoad按钮下载更新资源

    public IEnumerator DownAssetImpl()
    {
        var downloadsize = Addressables.GetDownloadSizeAsync(_updateKeys);
        yield return downloadsize;
        Debug.Log("start download size :" + downloadsize.Result);

        if (downloadsize.Result > 0)
        {
            var download = Addressables.DownloadDependenciesAsync(_updateKeys, Addressables.MergeMode.Union);
            yield return download;
            //await download.Task;
            Debug.Log("download result type " + download.Result.GetType());
            foreach (var item in download.Result as List<UnityEngine.ResourceManagement.ResourceProviders.IAssetBundleResource>)
            {
                var ab = item.GetAssetBundle();
                Debug.Log("ab name " + ab.name);
                foreach (var name in ab.GetAllAssetNames())
                {
                    Debug.Log("asset name " + name);
                }
            }
            Addressables.Release(download);
        }
        Addressables.Release(downloadsize);
    }

    public void DownLoad()
    {
        StartCoroutine(DownAssetImpl());
    }

在这里插入图片描述
在这里插入图片描述

Addressables.GetDownloadSizeAsync(_updateKeys)这个接口可以获取到需要下载的文件的总大小,而传入的_updateKeys是之前Addressables.UpdateCatalogs(catalogs, false)的返回值,这里面包含了需要更新的内容的key,我们也可以在这里进行筛选,假如有些资源是你不想更新的.接着调用Addressables.DownloadDependenciesAsync(_updateKeys, Addressables.MergeMode.Union)来进行真正的资源下载,注意这里有个坑,这个API返回的句柄不能用Task,会报空,不知道原因,也许是bug.当前版本1.8.5.
可以看到服务器上的日志又多了两条,说明我的客户端请求了这两个AB包.这与我们的预期是一样的,local和remote的静态包的内容都已经跑到了contentupdate这个AB包里了,remote的非静态包已经被覆盖更新了,被存放在服务器的资源目录中,而local的非静态包,被存放在Library/com.unity.addressables/StreamingAssetsCopy/aa/Android目录中,没有在服务器的资源目录中,所以这个包肯定是无法被更新的.下面我们再分别点击4个加载按钮测试下结果.
在这里插入图片描述

可以看到local static 和 remote static 已经通过contentupdate被正常下载更新,而remote non static是直接被覆盖了ab包更新.只有local non static 在加载的时候抛出了异常,无法加载.这里可能和大家想象的不一样,觉得local non static应该是用的老的资源来加载,其实不是.因为catalog文件被更新了,前面说过catalog文件会记录所有AB包的哈希值以及加载地址,当前catalog文件记录到local non static 的hash值是最新的,而我们当前留在手机上的local non static AB包却是之前的,而且这个AB包在catalog上记录的地址是在本地,无法向远程服务器下载.当AA系统发现hash值与AB包对应不上时,就当成资源缺失,自然就加载不出来这个资源了.


总结

  1. 注意更新资源时要使用Update a Previous Build来生成AB包,如果使用Build重新打包,那也会重新生成catalog文件,而之前发布的应用程序是无法下载新的catalog文件
  2. local non static 的Group是无法被AA系统更新的,万一不小心改到了这个Group了,并且使用了Update a Previous Build,那客户端会莫名其妙无法加载资源,所以强烈反对使用这种Group.官方文档上也忽略了这种Group.
  3. 不推荐使用static的Group,因为后续更新需要动到Group的结构,管理起来实在太麻烦.但是使用Remote Non Static的Group又必须一开始把资源放在远程服务器上,一般情况下,可能我们还是希望资源在发布时就带进包里,然后在修改后,再更新AB包.可能默认的更新方式不能满足我们,应该可以通过扩展AA系统来实现,这个可以后续讨论.
  • 19
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值