ET框架---BundleDownloaderComponent学习笔记

BundleDownloaderComponent学习笔记

请大家关注我的微博:@NormanLin_BadPixel坏像素


这应该就是热更新的包下载相关的内容了。我们知道,每次我们加载热更新的资源,需要判断本地和服务器的版本,如果本地的版本过低,则需要从服务端重新下载。

UnityWebRequestAsync学习笔记

我们来看一下热更新资源版本信息的结构吧。

VersionConfig

public int Version;

public long TotalSize;

public List<FileVersionInfo> FileVersionInfos = new List<FileVersionInfo>();

我们看到,储存了第几个版本的信息,储存了资源的全部大小,还储存了各个资源的文件信息,FileVersionInfo

public class FileVersionInfo
{
    public string File;
    public string MD5;
    public long Size;
}

也就是说,我们每次更新版本的时候不会更新全部的资源,而是可以根据FileVersionInfoMD5决定是否需要更新指定资源。

具体是怎么实现的呢?我们继续往下看代码。

我们先通过UnityWebRequestAsync获取服务器上热更资源的版本,再对比本地的版本信息。如果本地没有版本(第一次运行),则所有的资源都需要更新。否则,先用简单的文件读取File.ReadAllText() 来获取本地的版本信息。(以上的版本信息都是获取到字符串用Json反序列化成VersionConfig对象的)

// 先删除服务器端没有的ab
foreach (FileVersionInfo fileVersionInfo in localVersionConfig.FileVersionInfos)
{
    if (this.VersionConfig.FileInfoDict.ContainsKey(fileVersionInfo.File))
    {
        continue;
    }
    string abPath = Path.Combine(PathHelper.AppHotfixResPath, fileVersionInfo.File);
    File.Delete(abPath);
}

// 再下载
foreach (FileVersionInfo fileVersionInfo in this.VersionConfig.FileVersionInfos)
{
    FileVersionInfo localVersionInfo;
    if (localVersionConfig.FileInfoDict.TryGetValue(fileVersionInfo.File, out localVersionInfo))
    {
        if (fileVersionInfo.MD5 == localVersionInfo.MD5)
        {
            continue;
        }
    }

    if(fileVersionInfo.File == "Version.txt")
    {
        continue;
    }

    this.bundles.Enqueue(fileVersionInfo.File);
    this.TotalSize += fileVersionInfo.Size;
}

作者注释的很详细了,先在本地删除服务器端没有的ab,再下载。这里的下载其实是登记需要下载的名单。然后我们转到WaitAsync

private Task<bool> WaitAsync()
{
    if (this.bundles.Count == 0 && this.downloadingBundle == "")
    {
        return Task.FromResult(true);
    }

    this.Tcs = new TaskCompletionSource<bool>();

    UpdateAsync();

    return this.Tcs.Task;
}

经过上一步对比本地与服务器的版本,我们已经知道哪些资源是需要重新下载的。如果全部已经下载完了,则异步返回true。如果还有需要下载的,则开始异步下载。UpdateAsync,并返回his.Tcs.Task。我们知道,我们可以在下载完成的时候主动去结束这个Task。

UpdateAsync代码很长,我也全部帖出来了,我觉得应该很重要。我就在代码上面直接加注释帮助大家理解好了。

private async void UpdateAsync()
{
    while (true)
    {
        //如果所有的资源都下载完成了,则跳出循环
        if (this.bundles.Count == 0)
        {
            break;
        }
        //取出第一个需要重新下载的资源名,保存在downloadingBundle
        this.downloadingBundle = this.bundles.Dequeue();

        while (true)
        {
            //尝试去下载指定的资源
            try
            {
                //创建一个UnityWebRequestAsync
                using (this.downloadingRequest = ComponentFactory.Create<UnityWebRequestAsync>())
                {
                    //开始异步下载指定资源
                    await this.downloadingRequest.DownloadAsync(GlobalConfigComponent.Instance.GlobalProto.GetUrl() + "StreamingAssets/" + this.downloadingBundle);
                    //在资源下载完成后,获取资源的数据。
                    byte[] data = this.downloadingRequest.Request.downloadHandler.data;
                    //获取资源完整的路径名
                    string path = Path.Combine(PathHelper.AppHotfixResPath, this.downloadingBundle);
                    //如果发现资源所在的文件夹在本地没有,则先在本地创建文件夹
                    if (!Directory.Exists(Path.GetDirectoryName(path)))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(path));
                    }
                    //把资源数据保存到本地。FileMode.Create 指示操作系统应创建新文件,如果文件已经存在,它将被覆盖
                    using (FileStream fs = new FileStream(path, FileMode.Create))
                    {
                        fs.Write(data, 0, data.Length);
                    }
                }
            }
            catch(Exception e)
            {
                Log.Error($"download bundle error: {this.downloadingBundle}\n{e}");
                continue;
            }

            break;
        }
        //记录已经下载完的资源包,初始化一些内容,并开始下一个循环下载下一个资源包
        this.downloadedBundles.Add(this.downloadingBundle);
        this.downloadingBundle = "";
        this.downloadingRequest = null;
    }
    //待所有资源下载完成后,更新本地的"Version.txt"为服务器的版本
    using (FileStream fs = new FileStream(Path.Combine(PathHelper.AppHotfixResPath, "Version.txt"), FileMode.Create))
    using (StreamWriter sw = new StreamWriter(fs))
    {
        sw.Write(MongoHelper.ToJson(this.VersionConfig));
    }
    //当所有步骤完成后,我们手动结束this.Tcs,并返回true。
    this.Tcs?.SetResult(true);
}

这样,一套完整的热更资源系统就完成了。

另外,作者还好心的提供了一个获取下载进度的方法public int Progress,这里就不讲了,大家自己看看就能明白了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值