U4S4L17——自定义更新目录和下载AB包

本章代码关键字

1
2
3
4
Addressables.UpdateCatalogs()                //更新目录,如果不传入由CheckForCatalogUpdates()获取的需要更新的目录字符串,则自动检查目录是否有更新
Addressables.CheckForCatalogUpdates() //检查哪些目录需要更新,并将需要更新的目录字符串加载出来
Addressables.GetDownloadSizeAsync() //传入要加载的资源的标签或者资源名,加载其对应的包的大小(字节数)
Addressables.DownloadDependenciesAsync() //传入要加载的资源的标签或者资源名,提前加载其对应的包

目录的作用

目录文件的本质是Json文件和一个Hash文件(只存在于远端打包中)

image

其中记录的主要内容有:

  • Json文件中记录的是:

    1. 加载AB包、图集、资源、场景、实例化对象所用的脚本(会通过反射去加载他们来使用)
    2. AB包中所有资源类型对应的类(会通过反射去加载他们来使用)
    3. AB包对应路径
    4. 资源的path名

    等等

  • Hash文件中记录的是:

    目录文件对应hash码(每一个文件都有一个唯一码,用来判断文件是否变化)
    更新时本地的文件hash码会和远端目录的hash码进行对比,如果发现不一样就会更新目录文件

当我们使用远端发布内容时,在资源服务器也会有一个目录文件
Addressables会在运行时自动管理目录
如果远端目录发生变化了(他会通过hash文件里面存储的数据判断是否是新目录)
它会自动下载新版本并将其加载到内存中

手动更新目录

目录更新 我们一般都会放在进入游戏开始游戏之前,用于指导AB包的更新

  1. 如果要手动更新目录 建议在设置中关闭自动更新

    image

  2. 自动检查所有目录是否有更新,并更新目录API

    该方法同样返回的是AsyncOperationHandle<>​,其内部要加载的资源就是更新的列表

    UpdateCatalogs()​方法存在一个释放自动释放目录的参数,默认为true​,
    因此我们可以不手动释放更新出来的目录

    该方法配合CheckForCatalogUpdates()​可以更新指定的目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void Start()
    {
    //异步更新目录,自动检查所有目录是否有更新,返回值是AsyncOperationHandle<>
    Addressables.UpdateCatalogs(true).Completed += (obj) =>
    {
    //释放目录文件
    //(UpdateCatalogs方法存在一个释放自动释放目录的参数,默认为true,因此我们可以不手动释放更新出来的目录)
    //Addressables.Release(obj);
    };
    }
  3. 获取目录列表,再更新目录

    该方法同样返回的是AsyncOperationHandle<>​,其内部要加载的资源就是需要更新的目录的字符串列表
    将加载出来的目录字符串列表传入到UpdateCatalogs()​方法,UpdateCatalogs()​方法就会根据传入的目录列表来更新目录

    CheckForCatalogUpdates()​方法同样存在释放自动释放加载出来的字符串字符串的参数,默认为true​,
    因此我们可以不手动释放加载出来的目录字符串

    相比直接使用UpdateCatalogs()​方法,我们可以更加自定义的更新目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Addressables.CheckForCatalogUpdates().Completed += (obj) =>
    {
    //如果加载出来的目录字符串列表大于0,就证明存在可以更新的目录
    if (obj.Result.Count > 0)
    {
    //根据加载出来的目录列表,更新目录
    Addressables.UpdateCatalogs(obj.Result).Completed += (handle) =>
    {
    //更新完毕需要释放目录列表和字符串
    //(CheckForCatalogUpdates方法存在一个释放自动释放目录的参数,默认为true,因此我们可以不手动释放)
    Addressables.Release(handle);
    Addressables.Release(obj);
    };
    }
    };

预加载包

一般我们会在 刚进入游戏时 或者 切换场景时 显示一个Loading界面
我们可以在此时提前加载包,这样之后在使用资源就不会出现明显的异步加载延迟感

预加载包可以让我们在指定的时间提前加载或者下载包,而不需要在玩家游玩时创建对象时加载包,导致降低玩家游玩体验

首先需要通过Addressables.GetDownloadSizeAsync()​来获取需要加载包的大小,该方法可以传入资源名,标签名,或者两者的组合
该方法返回的是AsyncOperationHandle<long>​,返回的就是包的字节数,可通过字节数是否为0判断是否可以预加载包

然后再通过Addressables.DownloadDependenciesAsync()​预加载对应资源的包,
该方法需要传入资源名,标签名,或者两者的组合,参数和Addressables.LoadAssetsAsync<>()​差不多
该方法返回的是AsyncOperationHandle​,可通过返回值调用asyncOperationHandle<>.GetDownloadStatus()​来获取下载进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void Start()
{
StartCoroutine(LoadAsset());
}

IEnumerator LoadAsset()
{
//首先获取下载包的大小,可以传资源名、标签名、或者两者的组合
AsyncOperationHandle<long> handleSize = Addressables.GetDownloadSizeAsync(new List<string> { "Cube", "Sphere", "SD" });
yield return handleSize;
//预加载
if (handleSize.Result > 0)
{
//这样就可以异步加载,所有依赖的AB包相关内容了
AsyncOperationHandle handle = Addressables.DownloadDependenciesAsync(
new List<string> { "Cube", "Sphere", "SD" },
Addressables.MergeMode.Union);
while (!handle.IsDone)
{
//获取加载进度
DownloadStatus info = handle.GetDownloadStatus();
print(info.Percent);
print(info.DownloadedBytes + "/" + info.TotalBytes);
yield return 0;
}
//待AB包资源使用完毕,即可卸载加载的AB包
Addressables.Release(handle);
}
}