Unity 使用UnityWebRequest下载超大资源,实现断点续传和分段下载。

Posted 韭本菜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 使用UnityWebRequest下载超大资源,实现断点续传和分段下载。相关的知识,希望对你有一定的参考价值。

最近有个项目需要在服务器下载视频资源到本地,然后在本地播放视频,一开始看Unity官方文档找到资源下载的方法,但是在下载超大资源(一个2.8G的.mp4格式的视频)的时候回出现未知错误导致视频不能下载下来,先看官方提供的方法如下。

 

using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

public class FileDownloader : MonoBehaviour {

    void Start () {
        StartCoroutine(DownloadFile());
    }

    IEnumerator DownloadFile() {
        var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);
        string path = Path.Combine(Application.persistentDataPath, "unity3d.html");
        uwr.downloadHandler = new DownloadHandlerFile(path);
        yield return uwr.SendWebRequest();
        if (uwr.result != UnityWebRequest.Result.Success)
            Debug.LogError(uwr.error);
        else
            Debug.Log("File successfully downloaded and saved to " + path);
    }
}

于是我们采用断点续传和分段下载来实现超大资源的下载。

断点续传

户端软件断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度。

思路

获取到资源的总长度,获取到当前已经下载的长度,当下载中断再次请求下载的时候,先判断有没有下载完成,如果没有下载完成,从当前位置开始,下载剩下的资源。

GetResponseHeader("Content-Length")获取到资源的大小,下图中name=ueno&age=37正好是16个字节。这样我们就能获取到资源的总字节数。

SetRequestHeader("Range", "bytes=" + fileLength + "-")请求网络数据从第fileLength到最后的字节;

完整代码

代码注释已经比较详细

using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class FileDownloader : MonoBehaviour
{
    public Text text;
    private string MyURL = "http://education.jnaw.top/lubozhibouploaded/quanjing/1615791915263.mp4";
    //private string MyURL = "http://education.jnaw.top/lubozhibouploaded/quanjing/1629796505018.mp4";
    //十亿字节为一段
    double loadedBytes = 1000000000;
    void Start()
    {
        Debug.Log(Application.persistentDataPath);

        StartCoroutine(BreakpointResume(MyURL, Application.persistentDataPath + "/MP4/1615791915263.mp4"));

    }

    /// <summary>
    /// 分段,断点下载文件
    /// </summary>
    /// <param name="loadPath">下载地址</param>
    /// <param name="savePath">保存路径</param>
    /// <returns></returns>
    IEnumerator BreakpointResume(string loadPath, string savePath)
    {
        //UnityWebRequest 经配置可传输 HTTP HEAD 请求的 UnityWebRequest。
        UnityWebRequest headRequest = UnityWebRequest.Head(loadPath);
        //开始与远程服务器通信。
        yield return headRequest.SendWebRequest();

        if (!string.IsNullOrEmpty(headRequest.error))
        {
            Debug.LogError("获取不到资源文件");
            yield break;
        }
        //获取文件总大小
        ulong totalLength = ulong.Parse(headRequest.GetResponseHeader("Content-Length"));
        Debug.Log("获取大小" + totalLength);
        headRequest.Dispose();
        UnityWebRequest Request = UnityWebRequest.Get(loadPath);
        //append设置为true文件写入方式为接续写入,不覆盖原文件。
        Request.downloadHandler = new DownloadHandlerFile(savePath, true);
        //创建文件
        FileInfo file = new FileInfo(savePath);
        //当前下载的文件长度
        ulong fileLength = (ulong)file.Length;

        //请求网络数据从第fileLength到最后的字节;
        Request.SetRequestHeader("Range", "bytes=" + fileLength + "-");

        if (!string.IsNullOrEmpty(Request.error))
        {
            Debug.LogError("下载失败" + Request.error);
        }
        if (fileLength < totalLength)
        {
            Request.SendWebRequest();
            while (!Request.isDone)
            {
                double progress = (Request.downloadedBytes + fileLength) / (double)totalLength;
                text.text = (progress * 100 + 0.01f).ToString("f2") + "%";
                // Debug.Log("下载量" + Request.downloadedBytes);
                //超过一定的字节关闭现在的协程,开启新的协程,将资源分段下载
                if (Request.downloadedBytes >= loadedBytes)
                {
                    StopCoroutine("BreakpointResume");

                    //如果 UnityWebRequest 在进行中,就停止。
                    Request.Abort();
                    if (!string.IsNullOrEmpty(Request.error))
                    {
                        Debug.LogError("下载失败" + Request.error);
                    }
                    yield return StartCoroutine(BreakpointResume(loadPath, savePath));
                }

               
                yield return null;
            }
        }
        if (string.IsNullOrEmpty(Request.error))
        {
            Debug.Log("下载成功" + savePath);
            text.text = "100%";
        }


      
        //表示不再使用此 UnityWebRequest,并且应清理它使用的所有资源。
        Request.Dispose();
    }
}

以上是关于Unity 使用UnityWebRequest下载超大资源,实现断点续传和分段下载。的主要内容,如果未能解决你的问题,请参考以下文章

Unity 之 使用UnityWebRequest获取网络时间

HttpClient 和 Unity 的 UnityWebRequest/WWW API 的区别

Unity 之 使用UnityWebRequest.Get(“0“)结果得到“Accept“的问题记录

unity unitywebrequest 好用么

Unity Android 使用UnityWebRequest Post 数据后,没有获得服务器返回的数据

在硬盘中下载 AssetBundle