长江后浪推前浪,UnityWebRequest替代WWW

什么时候用HttpWebRequest

在Unity中,我们可以用系统的WWW或者HttpWebRequest来实现文件的下载。
因为WWW不存在设置timeout属性,因此当我们网络不好请求超时的时候,无法简单的做出判断。
当网络极差的时候,游戏下载将会停止(即一直在等待yield return www)当时间较长时网络恢复将无法继续下载,也没有提示,需要重启才能重新下载。
Unity早在5.4版本的时候就出了新的API UnityWebRequest用于替代WWW
有些较大的文件下载需要断点续传的功能(即下载了一部分突然中断下载后,再次下载直接从上次下载的地方继续下载,而不是重新下载),就需要使用HttpWebRequest


介绍

UnityWebRequest 由三个元素组成:

  1. UploadHandler 处理数据将数据上传到服务器的对象
  2. DownloadHandler 从服务器下载数据的对象
  3. UnityWebRequest 负责与HTTP 通信并管理上面两个对象。

UnityWebRequest支持与上传下载断点续传功能


常用方法

方法 作用
SendWebRequest() 开始与远程服务器通信。在调用此方法之后,有必要的话UnityWebRequest将执行DNS解析,将HTTP请求发送到目标URL的远程服务器并处理服务器的响应。
Get(url) 创建一个http为传入url的 UnityWebRequest 对象
Post(url) 向Web服务器发送表单信息
Put(url) 将数据上传到 Web 服务器
Abort() 直接结束联网
Head() 创建一个为传输HTTP头请求的 UnityWebRequest 对象
GetResponseHeader() 返回一个字典,内容为在最新的 HTTP 响应中收到的所有响应头

构造函数

public UnityWebRequest(); 
public UnityWebRequest(Uri uri);
public UnityWebRequest(Uri uri,string method);
public UnityWebRequest(Uri uri,string method,Networking.DownloadHandler downloadHandler, Networking.UploadHandler uploadHandler);

参数
解释一下参数的含义:

参数 含义
method 相当于方法名,只有GET,POST,PUT,HEAD四种,默认为GET,一旦调用SendWebRequest(),就无法更改
downloadHandler 下载数据的委托方法
uploadHandler 上传数据的委托方法

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

/// 
/// 网络请求测试
/// 
public class ChinarWebRequest : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(SendRequest());
    }

    /// 
    /// 开启一个协程,发送请求
    /// 
    /// 
    IEnumerator SendRequest()
    {
        Uri uri = new Uri("http://www.baidu.com"); //Uri 是 System 命名空间下的一个类,注意引用该命名空间
        UnityWebRequest uwr = new UnityWebRequest(uri);        //创建UnityWebRequest对象
        uwr.timeout = 5;
        yield return uwr.SendWebRequest();                     //等待返回请求的信息
        if (uwr.isHttpError || uwr.isNetworkError)             //如果其 请求失败,或是 网络错误
        {
            Debug.LogError(uwr.error); //打印错误原因
        }
        else //请求成功
        {
            Debug.Log("请求成功");
        }
    }
}

Get方法

Get 方法为创建一个http为传入url的 UnityWebReqest 对象

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


/// 
/// 网络请求测试
/// 
public class ChinarWebRequest : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(SendRequest());
    }

    /// 
    /// 开启一个协程,发送请求
    /// 
    /// 
    IEnumerator SendRequest()
    {
        UnityWebRequest uwr = UnityWebRequest.Get("http://www.baidu.com"); //创建UnityWebRequest对象
        yield return uwr.SendWebRequest();                                 //等待返回请求的信息
        if (uwr.isHttpError || uwr.isNetworkError)                         //如果其 请求失败,或是 网络错误
        {
            Debug.Log(uwr.error); //打印错误原因
        }
        else //请求成功
        {
            Debug.Log("Get:请求成功");
            Debug.Log(uwr.downloadedBytes);
        }
    }
}

Post方法

Post方法将一个表上传到远程的服务器,一般来说我们登陆某个网站的时候会用到这个方法,我们的账号密码会以一个表单的形式传过去

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

/// 
/// 网络请求测试
/// 
public class ChinarWebRequest : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Post());
    }
    /// 
    /// 开启一个协程,发送请求
    /// 
    /// 
    IEnumerator Post()
    {
        WWWForm form = new WWWForm();
        //键值对
        form.AddField("key",  "value");
        form.AddField("name", "Chinar");
        //请求链接,并将form对象发送到远程服务器
        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("发送成功"); 
        }
    }
}

Put方法

Put方法将数据发送到远程的服务器

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

/// 
/// 网络请求测试
/// 
public class ChinarWebRequest : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Upload());
    }
    
    /// 
    /// 开启协程
    /// 
    /// 
    IEnumerator Upload()
    {
        byte[] myData = System.Text.Encoding.UTF8.GetBytes("Chinar的测试数据");
        using (UnityWebRequest uwr = UnityWebRequest.Put("http://www.baidu.com", myData))
        {
            yield return uwr.SendWebRequest();

            if (uwr.isNetworkError || uwr.isHttpError)
            {
                Debug.Log(uwr.error);
            }
            else
            {
                Debug.Log("上传成功!");
            }
        }
    }
}

Abort方法

Abort 方法会尽快结束联网,可以随时调用此方法。
如果 UnityWebRequest 尚未完成,那么 UnityWebRequest 将尽快停止上传或下载数据。 中止的 UnityWebRequests 被认为遇到了系统错误。
isNetworkError或isHttpError属性将返回true,error属性将为 “User Aborted”。

Head方法

Head方法与Get方法用法一致,都是传入一个Url

/// 
/// 开启一个协程,发送请求
/// 
/// 
IEnumerator SendRequest1()
{
	UnityWebRequest uwr = UnityWebRequest.Head("http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建UnityWebRequest对象
	yield return uwr.SendWebRequest();                                 //等待返回请求的信息
	if (uwr.isHttpError || uwr.isNetworkError)                         //如果其 请求失败,或是 网络错误
	{
		Debug.Log(uwr.error); //打印错误原因
	}
	else //请求成功
	{
		Debug.Log("Head:请求成功");
	}
}

GetResponseHeader方法

GetResponseHeader方法可以用来获取请求文件的长度 传入参数 “Content-Length” 字符串,表示获取文件内容长度。

/// 
/// 开启一个协程,发送请求
/// 
/// 
IEnumerator SendRequest1()
{
    UnityWebRequest uwr = UnityWebRequest.Head("http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建UnityWebRequest对象
    yield return uwr.SendWebRequest();                                 //等待返回请求的信息
    if (uwr.isHttpError || uwr.isNetworkError)                         //如果其 请求失败,或是 网络错误
    {
        Debug.Log(uwr.error); //打印错误原因
    }
    else //请求成功
    {
    	long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
        Debug.Log("totalLength");//打印文件长度
    }
}

常用属性

属性 类型 含义
timeout int 等待时间(秒)超过此数值是 UnityWebReqest 的尝试连接将终止
isHttpError bool http响应出现出现错误
isNetworkError bool 系统出现错误
error string 描述 UnityWebRequest 对象在处理HTTP请求或响应时遇到的任何系统错误
downloadProgress float 表示从服务器下载数据的进度
uploadProgress float 表示从服务器上传数据的进度
isDone bool 是否完成与远程服务器的通信

下载文件

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

public class ChinarDownLoadFile : MonoBehaviour
{
    public Slider ProgressBar; //进度条
    public Text SliderValue; //滑动条值
    
    private Button startBtn;    //开始按钮

    void Start()
    {
        //初始化进度条和文本框
        ProgressBar.value = 0;
        SliderValue.text = "0.0%";
        startBtn = GameObject.Find("Start Button").GetComponent<Button>();
        startBtn.onClick.AddListener(OnClickStartDownload);
    }


    /// 
    /// 回调函数:开始下载
    /// 
    public void OnClickStartDownload()
    {
        StartCoroutine(DownloadFile());
    }


    /// 
    /// 协程:下载文件
    /// 
    IEnumerator DownloadFile()
    {
        UnityWebRequest uwr = UnityWebRequest.Get("http://www.linxinfa.test.mp4.mp4"); //创建UnityWebRequest对象,将Url传入
        uwr.SendWebRequest();                                                                                  //开始请求
        if (uwr.isNetworkError || uwr.isHttpError)                                                             //如果出错
        {
            Debug.Log(uwr.error); //输出 错误信息
        }
        else
        {
            while (!uwr.isDone) //只要下载没有完成,一直执行此循环
            {
                ProgressBar.value = uwr.downloadProgress; //展示下载进度
                SliderValue.text  = Math.Floor(uwr.downloadProgress * 100) + "%";
                yield return 0;
            }

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

            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)
    {
        Stream   sw;
        FileInfo file = new FileInfo(path);
        if (!file.Exists)
        {
            sw = file.Create();
        }
        else
        {
            return;
        }

        sw.Write(bytes, 0, length);
        sw.Close();
        sw.Dispose();
    }
}

断点续传

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

public class ChinarBreakpointRenewal : MonoBehaviour
{
    private bool _isStop;       //是否暂停

    public Slider ProgressBar; //进度条
    public Text SliderValue; //滑动条值
    private Button startBtn;    //开始按钮
    private Button pauseBtn;    //暂停按钮
    public string Url = "http://www.linxinfa.test.mp4";

    /// 
    /// 初始化UI界面及给按钮绑定方法
    /// 
    void Start()
    {
        //初始化进度条和文本框
        ProgressBar.value = 0;
        SliderValue.text = "0.0%";
        startBtn = GameObject.Find("Start Button").GetComponent<Button>();
        startBtn.onClick.AddListener(OnClickStartDownload);
        pauseBtn = GameObject.Find("Pause Button").GetComponent<Button>();
        pauseBtn.onClick.AddListener(OnClickStop);
    }


    /// 
    /// 回调函数:开始下载
    /// 
    public void OnClickStartDownload()
    {
    	// 注意真机上要用Application.persistentDataPath
        StartCoroutine(DownloadFile(Url, Application.streamingAssetsPath + "/MP4/test.mp4", CallBack));
    }


    /// 
    /// 协程:下载文件
    /// 
    /// 请求的Web地址
    /// 文件保存路径
    /// 下载完成的回调函数
    /// 
    IEnumerator DownloadFile(string url, string filePath, Action callBack)
    {
        UnityWebRequest huwr = UnityWebRequest.Head(url); //Head方法可以获取到文件的全部长度
        yield return huwr.SendWebRequest();
        if (huwr.isNetworkError || huwr.isHttpError) //如果出错
        {
            Debug.Log(huwr.error); //输出 错误信息
        }
        else
        {
            long   totalLength = long.Parse(huwr.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
            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; //当前文件长度
                Debug.Log(fs.Length);
                if (nowFileLength < totalLength)
                {
                    Debug.Log("还没下载完成");
                    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 (!uwr.isDone) //只要下载没有完成,一直执行此循环
                        {
                            if (_isStop) 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;
                                ProgressBar.value = (float) nowFileLength / totalLength;
                                SliderValue.text = Math.Floor((float) nowFileLength / totalLength * 100) + "%";
                                if (nowFileLength >= totalLength) //如果下载完成了
                                {
                                    ProgressBar.value = 1; //改变Slider的值
                                    SliderValue.text = 100 + "%";
                                    callBack?.Invoke();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /// 
    /// 下载完成后的回调函数
    /// 
    void CallBack()
    {
        Debug.Log("下载完成");
    }

    /// 
    /// 暂停下载
    /// 
    public void OnClickStop()
    {
        if (_isStop)
        {
            pauseBtn.GetComponentInChildren<Text>().text = "暂停下载";
            Debug.Log("继续下载");
            _isStop = !_isStop;
            OnClickStartDownload();
        }
        else
        {
            pauseBtn.GetComponentInChildren<Text>().text = "继续下载";
            Debug.Log("暂停下载");
            _isStop = !_isStop;
        }
    }
}

你可能感兴趣的:(unity3D)