Unity网络

基础概念

Unity网络

Unity 发送网络请求UnityWebRequest
UnityWebRequest 提供了一个模块化系统,用于构成 HTTP 请求和处理 HTTP 响应。UnityWebRequest 系统的主要目标是让 Unity 游戏与 Web 浏览器后端进行交互。
基本支持

  • 所有版本的 Unity 编辑器和某些播放器
  • WebGl
  • iOS 和 Android
  • 通用Windows PC端

UnityWebRequest 生态系统将 HTTP 事务分解为三个不同的操作:

  • 向服务器提供数据

  • 从服务器接收数据

  • HTTP 流量控制(例如,重定向和错误处理)

  • UploadHandler 对象处理数据到服务器的传输

  • DownloadHandler 对象处理从服务器接收的数据的接收、缓冲和后处理

  • UnityWebRequest 对象管理其他两个对象,还处理 HTTP 流量控制。此对象是定义自定义标头和 URL 的位置,也是存储错误和重定向信息的位置。

任何 HTTP 事务,正常的代码流程如下:

--- 创建 Web 请求对象
--- 配置 Web 请求对象
------ 设置自定义标头
------ 设置 HTTP 动词(例如 GET、POST 和 HEAD - 除 Android 之外的所有平台都允许使用自定义动词)
------ 设置 URL *(可选)创建上传处理程序并将其附加到 Web 请求
------ 提供要上传的数据
------ 提供要上传的 HTTP 表单 *(可选)创建下载处理程序并将其附加到 Web 请求
--- 发送 Web 请求
------ 如果在协程中,可获得 Send() 调用的结果以等待请求完成 (可选)读取从下载处理程序接收的数据 (可选)从 UnityWebRequest 对象中读取错误信息、HTTP 状态码和响应标头

代码示例

从 HTTP 服务器检索文本或二进制数据 (GET)
因为这里我没有部署 HTTP 文件服务器,所以这里使用的是官方的案例,如果看不太懂可以前往官方文档查看:https://docs.unity.cn/cn/2021.3/Manual/UnityWebRequest-RetrievingTextBinaryData.html
访问百度网址,并获取页面数据

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

public class MyBehaviour : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(GetText());
    }

    IEnumerator GetText()
    {
        UnityWebRequest www = UnityWebRequest.Get("https://www.baidu.com/");
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
        }
        else
        {
            // 以文本形式显示结果
            Debug.Log(www.downloadHandler.text);

            // 或者获取二进制数据形式的结果
            byte[] results = www.downloadHandler.data;
        }
    }
}

从 HTTP 服务器检索纹理 (GET)
此处展示的是获取百度 icon 并且将 icon 赋值给游戏对象的纹理, 注意因为是3D的物体,赋值时需要新建个材质保存纹理,再把材质赋值给需要更改的物体。

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

public class WWWRequestImg : MonoBehaviour
{
    
    private GameObject cube;
    void  Start()
    {
        cube = Resources.Load("Cube1") as GameObject;
    }

    public void UnityWebGetImage()
    {
        StartCoroutine(GetImage1("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"));
    }
    /// <summary>
    /// 使用UnityWebRequest获取图片
    /// </summary>
    /// <param name="url">图片地址</param>
    /// <returns></returns>
    public IEnumerator GetImage1(string url)
    {
        UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
        
        // 请求该网址内容
        yield return www.SendWebRequest();

        if(www.result == UnityWebRequest.Result.Success)
        {
            Texture2D texture = DownloadHandlerTexture.GetContent(www);
            // 将获取到的内容进行使用
            
            Material mat = new Material(Shader.Find("Standard"));
            mat.mainTexture = texture;
            GameObject gm = GameObject.Instantiate(cube);
            gm.transform.position = new Vector3(0, -2, 0);
            gm.transform.eulerAngles = new Vector3(0, 0, 180);
            gm.GetComponent<Renderer>().material = mat;
        }
        else
        {
            Debug.Log("请求失败");
        }
    }
}

从 HTTP 服务器下载 AssetBundle (GET)
下载 AB 包是游戏中最常见不过的事了,比如市面上许多大型游戏,在开始时都会检索客户端和服务端的AB包文件是否相同,如果不同则下载对应的AB包进行资源热更新, 像代码的热更新你就可以使用Lua编写代码然后塞到DLL包中。

  • 此函数将创建 UnityWebRequest 并将目标 URL 设置为提供的 URL 参数。此函数还会将 HTTP 动词设置为 GET,但不会设置任何其他标志或自定义标头。
  • 此函数将 DownloadHandlerAssetBundle 附加到 UnityWebRequest。此下载处理程序有一个特殊的 assetBundle 属性,一旦下载和解码了足够的数据,便可使用该属性来提取 AssetBundle,从而允许访问 AssetBundle 中的资源。
  • 如果提供版本号或 Hash128 对象作为参数,也会将这些参数传递给 DownloadHandlerAssetBundle。下载处理程序随后将采用缓存系统。

因为我并没有使用过这种方式获取AB包,所以只能学习官方案例怎么使用

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
 
public class MyBehaviour : MonoBehaviour {
    void Start() {
        StartCoroutine(GetAssetBundle());
    }
 
    IEnumerator GetAssetBundle() {
        UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle("https://www.my-server.com/myData.unity3d");
        yield return www.SendWebRequest();
 
        if (www.result != UnityWebRequest.Result.Success) {
            Debug.Log(www.error);
        }
        else {
            AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
        }
    }
}

将表单发送到 HTTP 服务器 (POST)
我们先想想,发送 Post 请求,一般需要用什么,首先是一个提交地址,其次是数据表头和数据, 只有满足这两个条件并且,通过服务器验证才会获得相应。
在 Unity 中, Unity提供了一个 IMultipartFormSection 接口由用户实现, Unity 还提供了数据和文件部分的默认实现MultipartFormDataSection 和 MultipartFormFileSection
UnityWebRequest.POST 的重载可接受成员必须全部是 IMultipartFormSections 的列表参数(作为第二个参数)
UnityWebRequest.Post(string url, List<IMultipartFormSection> formSections);

  • 此函数将创建 UnityWebRequest 并将目标 URL 设置为第一个字符串参数。此函数还会为 IMultipartFormSection 对象列表中所指定的表单数据相应设置 UnityWebRequest 的 Content-Type 标头。
  • 默认情况下,此函数将 DownloadHandlerBuffer 附加到 UnityWebRequest。这是为了方便起见,可用于检查服务器的应答。
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;

public class MyBehavior : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Upload());
    }

    IEnumerator Upload()
    {
        List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
        formData.Add(new MultipartFormDataSection("field1=foo&field2=bar"));
        formData.Add(new MultipartFormFileSection("my file data", "myfile.txt"));

        UnityWebRequest www = UnityWebRequest.Post("https://www.my-server.com/myform", formData);
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log("Form upload complete!");
        }
    }
}

将原始数据上传到 HTTP 服务器 (PUT)

发送原始数据 Unity 提供了两个函数

WebRequest.Put(string url, string data);
WebRequest.Put(string url, byte[] data);

看着很简单,用起来也不难。

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
 
public class MyBehavior : MonoBehaviour {
    void Start() {
        StartCoroutine(Upload());
    }
 
    IEnumerator Upload() {
        byte[] myData = System.Text.Encoding.UTF8.GetBytes("This is some test data");
        UnityWebRequest www = UnityWebRequest.Put("https://www.my-server.com/upload", myData);
        yield return www.SendWebRequest();
 
        if (www.result != UnityWebRequest.Result.Success) {
            Debug.Log(www.error);
        }
        else {
            Debug.Log("Upload complete!");
        }
    }
}

创建 UnityWebRequest
与任何其他对象一样,WebRequest 也可以实例化。可使用两个构造函数:

  • 标准的无参数构造函数将创建一个所有设置均为空或默认值的新 UnityWebRequest。此函数中不会设置目标 URL,不会设置自定义标头,并且重定向限制设置为 32。
  • 第二个构造函数采用一个字符串参数。此构造函数将 UnityWebRequest 的目标 URL 分配给字符串参数的值,除此之外,与无参数的构造函数相同。
UnityWebRequest wr = new UnityWebRequest(); // 完全为空
UnityWebRequest wr2 = new UnityWebRequest("https://www.mysite.com"); // 设置目标 URL

// 必须提供以下两项才能让 Web 请求正常工作
wr.url = "https://www.mysite.com";
wr.method = UnityWebRequest.kHttpVerbGET;   // 可设置为任何自定义方法,提供了公共常量

wr.useHttpContinue = false;
wr.chunkedTransfer = false;
wr.redirectLimit = 0;  // 禁用重定向
wr.timeout = 60;       // 此设置不要太小,Web 请求需要一些时间

创建 UploadHandler

  • 目前,仅一种类型的上传处理程序可用:UploadHandlerRaw。此类在构建时接受数据缓冲区。此缓冲区在内部复制到本机代码内存中,然后当远程服务器准备好接受主体数据时,此缓冲区由 UnityWebRequest 系统使用。
  • 上传处理程序还接受“Content Type”字符串。如果在 UnityWebRequest 自身中没有设置 Content-Type 标头,则此字符串用于 UnityWebRequest 的 Content-Type 标头值。如果在 UnityWebRequest 对象上手动设置了 Content-Type 标头,则将忽略上传处理程序对象上的 Content-Type。
  • 如果没有在 UnityWebRequest 或 UploadHandler 上设置 Content-Type,则系统会将 Content-Type 默认设置为 application/octet-stream。
byte[] payload = new byte[1024];
// ... 使用数据填充有效负载 ...

UnityWebRequest wr = new UnityWebRequest("https://www.mysite.com/data-upload");
UploadHandler uploader = new UploadHandlerRaw(payload);

// 发送标头:"Content-Type: custom/content-type";
uploader.contentType = "custom/content-type";

wr.uploadHandler = uploader;

DownloadHandlers 有多种类型:

  • DownloadHandlerBuffer 用于简单的数据存储。
  • DownloadHandlerFile 用于下载文件并将文件保存到磁盘(内存占用少)。
  • DownloadHandlerTexture 用于下载图像。
  • DownloadHandlerAssetBundle 用于提取 AssetBundle。
  • DownloadHandlerAudioClip 用于下载音频文件。
  • DownloadHandlerMovieTexture 用于下载视频文件。由于 MovieTexture 已被弃用,因此建议您使用 VideoPlayer 进行视频下载和电影播放。
  • DownloadHandlerScript 是一个特殊类。就其本身而言,不会执行任何操作。但是,此类可由用户定义的类继承。此类接收来自UnityWebRequest 系统的回调,然后可以使用这些回调在数据从网络到达时执行完全自定义的数据处理。

此处使用 DownloadHandlerTexture 获取下载的图片

  UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
  
  // 请求该网址内容
  yield return www.SendWebRequest();

  if(www.result == UnityWebRequest.Result.Success)
  {
      Texture2D texture = DownloadHandlerTexture.GetContent(www);
      // 将获取到的内容进行使用
      
      Material mat = new Material(Shader.Find("Standard"));
      mat.mainTexture = texture;
      GameObject gm = GameObject.Instantiate(cube);
      gm.transform.position = new Vector3(0, -2, 0);
      gm.transform.eulerAngles = new Vector3(0, 0, 180);
      gm.GetComponent<Renderer>().material = mat;
  }
  else
  {
      Debug.Log("请求失败");
  }
posted @ 2024-10-18 15:05  请明月  阅读(19)  评论(0编辑  收藏  举报