UnityWebRequest教程☀️2021,你还在使用过时的 www API吗?

在这里插入图片描述

目录

🟥  常用网络传输方法

1️⃣ Get下载数据

2️⃣ Post上传数据

3️⃣ Put上传数据

4️⃣ Head下载头文件

🟧 网络传输的API

1️⃣ 测试网址是否连通

2️⃣ 获取要下载数据的长度

3️⃣ 显示下载进度

4️⃣ 显示上传进度

5️⃣ 保存下载的文件

6️⃣ 断点续传


 

各位小老弟,可能已经遇到www协议过时的问题了

但又因为BestHttp是一个插件,在大型公司,不好直接将自己的插件放在项目中。

那么下面,我们就来看看Unity自己的最新网络传输方法:

UnityWebRequest

 

🟥  常用网络传输方法

网络传输一般采用Get、Post、Put、Head,

同时还有一些控制的API,或者得到数据之类的API,那么就先从Get说起

1️⃣ Get下载数据

Get可用来下载字符串、数组、图片、AB包、音频等的数据。

当下载完成,可再将数据进行你想要的转换。

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

    IEnumerator SendGetRequest()
    {
        UnityWebRequest uwr = UnityWebRequest.Get("http://www.baidu.com");
        yield return uwr.SendWebRequest();
        if (uwr.isHttpError || uwr.isNetworkError)
        {
            Debug.Log(uwr.error);
        }
        else //请求成功
        {
            Debug.Log("Get:请求成功");
            Debug.Log("下载的数据:" + uwr.downloadedBytes);
        }
    }

 

2️⃣ Post上传数据

Post可以键值对的形式,将数据存在表单WWWForm里,

来上传字符串、图片、音频等的数据。

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

    IEnumerator SendPostRequest()
    {
        WWWForm form = new WWWForm();
        form.AddField("key", "value");
        form.AddField("name", "Chinar");
        UnityWebRequest webRequest = UnityWebRequest.Post("http://www.baidu.com", form);

        yield return webRequest.SendWebRequest();
        if (webRequest.isHttpError || webRequest.isNetworkError)
        {
            Debug.Log(webRequest.error);
        }
        else
        {
            Debug.Log("发送成功");
        }
    }

 

3️⃣ Put上传数据

UnityWebRequest数据传输,除了一般我们用的最多的Post、Get,其实还有Put、Head

Post 和 Put 确实很相像,通俗解释就是-------

新建一条记录的话就用post,

更新一条记录的话就用put.

但你用Post更新数据也没问题。

Put上传的东西跟Post相同,同样可以上传音视频、字符串等数据。 

    void Start() {
        StartCoroutine(SendPutRequest());
    }
 
    //更新数据
    IEnumerator SendPutRequest() {
        byte[] myData = System.Text.Encoding.UTF8.GetBytes("This is some test data");
        UnityWebRequest www = UnityWebRequest.Put("http://www.my-server.com/upload", myData);
        yield return www.SendWebRequest();
 
        if(www.isNetworkError || www.isHttpError) {
            Debug.Log(www.error);
        }
        else {
            Debug.Log("Upload complete!");
        }
    }

 

4️⃣ Head下载头文件

Head跟Get类似,不同的是Head不会下载文件,只会得到头文件数据。

你可以先了解到这个文件的大小等信息,再让用户决定怎样操作。

使用方法:见下方的 “获取要下载数据的长度”。

 

 

🟧 网络传输的API

有些人又要说了,那我会传输方法了,那怎样怎样得到传输速度呢?

本段就开始讲解UnityWebRequest的各个实用的方法,或者API

1️⃣ 测试网址是否连通

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

    //测试网址是否连通
    IEnumerator SendRequest()
    {
        Uri uri = new Uri("http://www.baidu.com");
        UnityWebRequest uwr = new UnityWebRequest(uri);
        //等待时间(秒)  超过此数值时,UnityWebReqest的尝试连接将终止
        uwr.timeout = 5;
        yield return uwr.SendWebRequest();
        if (uwr.isHttpError || uwr.isNetworkError)
        {
            Debug.LogError("请求失败:" + uwr.error);
        }
        else //请求成功
        {
            Debug.Log("请求成功");
        }
    }

 

2️⃣ 获取要下载数据的长度

这个API通常用在要下载文件时,先显示要下载文件的大小。

比如《炉石》的是否更新界面、《和平精英》的新场景资源包界面

使用Head的好处是,Head会得到要下载数据的头文件,却不会下载文件。

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

    private IEnumerator SendHeadRequest(string url)
    {
        UnityWebRequest huwr = UnityWebRequest.Head(url);
        yield return huwr.SendWebRequest();
        if (huwr.isNetworkError || huwr.isHttpError) //如果出错
        {
            Debug.Log(huwr.error); //输出 错误信息
        }
        else
        {
            long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length"));
            print("文件的长度:"+totalLength);
        }
    }

 

3️⃣ 显示下载进度

    public void Start()
    {
        StartCoroutine(DownloadFile());
    }
    
    IEnumerator DownloadFile()
    {
        UnityWebRequest uwr = UnityWebRequest.Get("http://dpv.videocc.net/689be7713e/1/689be7713e7898052861311bd74fc831_3.mp4?pid=1611569020809X1563841");
        uwr.SendWebRequest();

        if (uwr.isNetworkError || uwr.isHttpError)
        {
            Debug.Log(uwr.error);
        }
        else
        {
            while (!uwr.isDone)
            {
                GetComponent<Slider>().value = uwr.downloadProgress;
                //Math.floor() 返回小于或等于一个给定数字的最大整数。
                GetComponent<Text>().text = Math.Floor(uwr.downloadProgress * 100) + "%";
                yield return 0;
            }

            if (uwr.isDone) //如果下载完成了
            {
                GetComponent<Slider>().value = 1; //改变Slider的值
                GetComponent<Text>().text = 100 + "%";
            }
        }
    }

注意哈,

我们跟上面的Get相比,要注意这儿就没有yield return webRequest.SendWebRequest()了,

而是直接 webRequest.SendWebRequest()

因为yield return后,是直接下载完成或者下载失败。但我们在这儿不需要等待,我们需要时刻知道下载进度。

 

4️⃣ 显示上传进度

跟下载进度类似,是将downloadProgress,变成了uploadProgress。

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

    IEnumerator SendPostRequest()
    {
        WWWForm form = new WWWForm();
        form.AddField("key", "value");
        form.AddField("name", "Chinar");
        UnityWebRequest webRequest = UnityWebRequest.Post("http://www.baidu.com", form);
        
        webRequest.SendWebRequest();
            
        if (webRequest.isNetworkError || webRequest.isHttpError)
        {
            Debug.Log(webRequest.error);
        }
        else
        {
            while (!webRequest.isDone)
            {
                GetComponent<Slider>().value = webRequest.uploadProgress;
                //Math.floor() 返回小于或等于一个给定数字的最大整数。
                GetComponent<Text>().text = Math.Floor(webRequest.uploadProgress * 100) + "%";
                yield return 0;
            }

            if (webRequest.isDone) //如果下载完成了
            {
                GetComponent<Slider>().value = 1; //改变Slider的值
                GetComponent<Text>().text = 100 + "%";
            }
        }
    }

 

 

5️⃣ 保存下载的文件

...
byte[] results = uwr.downloadHandler.data;
// 注意真机上要用Application.persistentDataPath
CreateFile(Application.streamingAssetsPath + "/MP4/test.mp4", results, uwr.downloadHandler.data.Length);
AssetDatabase.Refresh(); //刷新一下
...

    void CreateFile(string path, byte[] bytes, int length)
    {
        FileInfo file = new FileInfo(path);
        if (file.Exists)
            return;
        
        Stream sw;
        sw = file.Create();
        sw.Write(bytes, 0, length);
        sw.Close();
        sw.Dispose();
    }

 

 

6️⃣ 断点续传

断点续传的机制是通过Head先知道要下载文件的大小,然后Get进行下载。

若点了暂停下载,实际是通过break,取消了下载的StartCoroutine。再次开始下载是再次调用StartCoroutine下载。

但再次下载,会先检测本地文件的长度,然后将该长度传入下载请求,从该长度处后开始下载、写入文件,完成断点续传。

    public Button downloadBtn; //开始下载按钮
    public Button controBtn; //暂停下载与恢复下载按钮

    private string Url = "http://dpv.videocc.net/689be7713e/1/689be7713e7898052861311bd74fc831_3.mp4?pid=1611569020809X1563841";
    private bool _isPause;

    void Start()
    {
        downloadBtn.onClick.AddListener(StartDownload);
        controBtn.onClick.AddListener(DownLoadCon);
    }

    public void DownLoadCon()
    {
        if (_isPause)
        {
            _isPause = false;
            Debug.Log("当前继续开始下载");
            StartDownload();
        }
        else
        {
            _isPause = true;
            Debug.Log("当前已暂停下载");
        }
    }

    private void StartDownload()
    {
        // 注意真机上要用Application.persistentDataPath
        StartCoroutine(DownloadFile(Url, Application.streamingAssetsPath + "/MP4/test.mp4"));
    }

    private IEnumerator DownloadFile(string url, string filePath)
    {
        UnityWebRequest huwr = UnityWebRequest.Head(url);
        yield return huwr.SendWebRequest();
        if (huwr.isNetworkError || huwr.isHttpError)
        {
            Debug.Log(huwr.error);
        }
        else
        {
            long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length"));
            print("文件的全部长度:" + totalLength);

            string dirPath = Path.GetDirectoryName(filePath);
            if (!Directory.Exists(dirPath)) //判断路径是否存在
            {
                Directory.CreateDirectory(dirPath);
            }

            //创建一个文件流,指定路径为filePath,模式为打开或创建,访问为写入
            using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                long nowFileLength = fs.Length; //当前本地的文件长度
                if (nowFileLength < totalLength)
                {
                    // FileStream.Seek:从当前文件一开始,向后移动nowFileLength个字节,将该流的当前位置设置为给定值。
                    fs.Seek(nowFileLength, SeekOrigin.Begin);
                    UnityWebRequest uwr = UnityWebRequest.Get(url); //创建UnityWebRequest对象,将Url传入
                    uwr.SetRequestHeader("Range", "bytes=" + nowFileLength + "-" + totalLength);
                    uwr.SendWebRequest();

                    if (uwr.isNetworkError || uwr.isHttpError)
                    {
                        Debug.Log(uwr.error);
                    }
                    else
                    {
                        long index = 0;
                        while (nowFileLength < totalLength) //只要下载没有完成,一直执行此循环
                        {
                            print(nowFileLength);
                            if (_isPause)    //暂停下载
                                break;
                            yield return null;
                            byte[] data = uwr.downloadHandler.data;
                            if (data != null)
                            {
                                long length = data.Length - index;
                                fs.Write(data, (int) index, (int) length);
                                index += length;
                                nowFileLength += length;
                                if (nowFileLength >= totalLength)
                                {
                                    print("下载完成!");
                                    AssetDatabase.Refresh();
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

小提示:

FileStream.Seek(long offset, SeekOrigin origin):有两个参数。第一参数规定文件指针以字节为单位移动的距离。第二个规定开始计算的位置

SeekOrigin是一个枚举,包含三个值:Begin、Current、End。

  • aFile.Seek(8,SeekOrigin.Begin)---------将文件的指针移动到第八个字节。起始位置就是文件的第一个字节
  • aFile.Seek(-5,SeekOrigin.End); 从文件的末尾向前查找五个字节
  • aFile.Seek(2,SeekOrigin.Current);

大家还有什么问题,欢迎在下方留言!


 

在这里插入图片描述


如果你有 技术的问题 或 项目开发

都可以加下方联系方式

和我聊一聊你的故事🧡

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值