前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >UnityWebRequest教程☀️2021,你还在使用过时的 www API吗?

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

作者头像
星河造梦坊官方
发布2024-08-15 19:39:12
发布2024-08-15 19:39:12
16200
代码可运行
举报
运行总次数:0
代码可运行

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

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

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

UnityWebRequest

🟥 常用网络传输方法

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

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

1️⃣ Get下载数据

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

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

代码语言:javascript
代码运行次数:0
运行
复制
    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里,

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

代码语言:javascript
代码运行次数:0
运行
复制
    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相同,同样可以上传音视频、字符串等数据。

代码语言:javascript
代码运行次数:0
运行
复制
    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️⃣ 测试网址是否连通
代码语言:javascript
代码运行次数:0
运行
复制
    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会得到要下载数据的头文件,却不会下载文件。

代码语言:javascript
代码运行次数:0
运行
复制
    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️⃣ 显示下载进度
代码语言:javascript
代码运行次数:0
运行
复制
    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。

代码语言:javascript
代码运行次数:0
运行
复制
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️⃣ 保存下载的文件
代码语言:javascript
代码运行次数:0
运行
复制
...
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下载。

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

代码语言:javascript
代码运行次数:0
运行
复制
    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);

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🟥 常用网络传输方法
    • 1️⃣ Get下载数据
    • 2️⃣ Post上传数据
    • 3️⃣ Put上传数据
    • 4️⃣ Head下载头文件
  • 🟧 网络传输的API
    • 1️⃣ 测试网址是否连通
    • 2️⃣ 获取要下载数据的长度
    • 3️⃣ 显示下载进度
    • 4️⃣ 显示上传进度
    • 5️⃣ 保存下载的文件
    • 6️⃣ 断点续传
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档