The UnityWebRequest is a replacement for Unity’s original WWW object. It provides a modular system for composing HTTP requests and handling HTTP responses. The primary goal of the UnityWebRequest system is to permit Unity games to interact with modern Web backends. It also supports high-demand features such as chunked HTTP requests, streaming POST/PUT operations and full control over HTTP headers and verbs.
For end-users who only employ common WWW use cases, transitioning to the new system should be almost a find-and-replace process.
The system consists of two layers. A Low-Level API (LLAPI) provides maximum flexibility for power users, while a High-Level API (HLAPI) wraps the Low-Level API and provides a convenient interface for performing common operations.
The UnityWebRequest system supports most Unity platforms, with the notable exception of the Unity Web Player.
Platforms supported in 5.2:
Platforms supported in 5.3:
Additional platform support will be rolled out in further 5.x releases:
The UnityWebRequest ecosystem breaks down an HTTP transaction into three distinct operations:
To provide a better interface for power users, these operations are each governed by their own objects:
UploadHandler
object handles transmission of data to the serverDownloadHandler
object handles receipt, buffering and postprocessing of data received from the serverUnityWebRequest object
, which manages the other two objects, and also handles HTTP flow control. This object is where custom headers and URLs are defined, and where error and redirect information is stored.For any given HTTP transaction, the generic code flow is:
Send()
call to wait for the request to complete, just like WWW.This section details the options available in the High-Level API, and the scenarios they are intended to address.
To retrieve simple data, such as textual data or binary data, from a standard HTTP or HTTPS web server, the call to use is UnityWebRequest.GET. This method takes a single string as an argument; the string specifies the URL from which data will be retrieved.
This method is analogous to the standard WWW constructor:
WWW myWww = new WWW("http://www.myserver.com/foo.txt");
// ... is analogous to ...
UnityWebRequest myWr = UnityWebRequest.Get("http://www.myserver.com/foo.txt");
This method creates a UnityWebRequest
and sets the target URL to the string argument. It sets no other custom flags or headers.
By default, this method attaches a standard DownloadHandlerBuffer
to the UnityWebRequest
. This handler will buffer the data received from the server and make it available to your scripts when the request is complete.
By default, this method attaches no UploadHandler
to the UnityWebRequest
. You may attach one manually if you wish.
Пример:
using UnityEngine;
using System.Collections;
+using UnityEngine.Networking;
class MyBehaviour: public MonoBehaviour {
void Start() {
StartCoroutine(GetText());
}
IEnumerator GetText() {
UnityWebRequest www = UnityWebRequest.Get("http://www.my-server.com");
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
// Show results as text
Debug.Log(www.downloadHandler.text);
// Or retrieve results as binary data
byte[] results = www.downloadHandler.data;
}
}
}
To retrieve a texture file from a remote server, you may use UnityWebRequest.Texture.
This method is very similar to UnityWebRequest.GET
, but is optimized for downloading and storing textures efficiently.
This method takes a single string as an argument. The string specifies the URL from which you wish to download an image file for use as a texture.
This method creates a UnityWebRequest
and sets the target URL to the string argument. This method sets no other flags or custom headers.
This method attaches a DownloadHandlerTexture
object to the UnityWebRequest
. DownloadHandlerTexture is a specialized Download Handler which is optimized for storing images which are to be used as textures in the Unity Engine. Using this class significantly reduces memory reallocation compared to downloading raw bytes and creating a texture manually in script.
By default, this method attaches on Upload Handler. You may add one manually if you wish.
Пример:
using UnityEngine;
using System.Collections;
class MyBehaviour: public MonoBehaviour {
void Start() {
StartCoroutine(GetTexture());
}
IEnumerator GetTexture() {
UnityWebRequest www = UnityWebRequest.GetTexture("http://www.my-server.com/image.png");
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
Texture myTexture = ((DownloadHandlerTexture)www.downloadHandler).texture;
}
}
}
Alternatively, you can implement GetTexture using a helper getter:
IEnumerator GetTexture() {
UnityWebRequest www = UnityWebRequest.GetTexture("http://www.my-server.com/image.png");
yield return www.Send();
Texture myTexture = DownloadHandlerTexture.GetContent(www);
}
To retrieve an asset bundle from a remote server, you may use UnityWebRequest.AssetBundle. This method streams data into an internal buffer, which decodes/decompresses the asset bundle’s data on a worker thread.
The method’s arguments take several forms. In its simplest form, it takes only the URL from which the asset bundle should be downloaded. You may optionally provide a checksum to verify the integrity of the downloaded data.
Alternately, if you wish to use the asset bundle caching system, you may provide either a version number or a Hash128 data structure. These are identical to the version numbers or Hash128 objects
provided to the old system via WWW.LoadFromCacheOrDownload
.
This method creates a UnityWebRequest
and sets the target URL to the supplied URL argument. It also sets the HTTP verb to GET
, but sets no other flags or custom headers.
This method attaches a DownloadHandlerAssetBundle
to the UnityWebRequest
. This download handler has a special assetBundle
property, which can be used to extract the asset bundle once enough data has been downloaded and decoded to permit access to the resources inside the bundle.
If you supply a version number or Hash128
object as arguments, it also passes those arguments to the DownloadHandlerAssetBundle
. The download handler will then employ the caching system.
Пример:
using UnityEngine;
using System.Collections;
class MyBehaviour: public MonoBehaviour {
void Start() {
StartCoroutine(GetAssetBundle());
}
IEnumerator GetAssetBundle() {
UnityWebRequest www = UnityWebRequest.GetAssetBundle("http://www.my-server.com/myData.unity3d");
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
AssetBundle bundle = ((DownloadHandlerAssetBundle)www.downloadHandler).assetBundle;
}
}
}
Alternatively, you can implement GetAssetBundle
using a helper getter:
IEnumerator GetTexture() {
UnityWebRequest www = UnityWebRequest.GetAssetBundle("http://www.my-server.com/myData.unity3d");
yield return www.Send();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
}
There are two primary methods for sending data to a server, formatted as an HTML Form.
To help migrate from the old WWW system, the new UnityWebRequest system permits you to use the old WWWForm object to provide form data.
In this case, the function signature is:
WebRequest.Post(string url, WWWForm formData);
This method creates a new UnityWebRequest
and sets the target URL to the first string argument’s value. It also reads any custom headers generated by the WWWForm
argument (such as Content-Type) and copies them into the UnityWebRequest
.
This method, by default, attaches a DownloadHandlerBuffer
to the UnityWebRequest
. This is for convenience: you can use this to check your server’s replies.
This method reads the raw data generated by the WWWForm object
and buffers it in an UploadHandlerRaw
object, which is attached to the UnityWebRequest
. Therefore, changes to the WWWForm
object after calling UnityWebRequest.POST
will not alter the contents of the UnityWebRequest
.
Пример:
using UnityEngine;
using System.Collections;
class MyBehavior: public MonoBehaviour {
void Start() {
StartCoroutine(Upload());
}
IEnumerator Upload() {
WWWForm form = new WWWForm();
form.AddField("myField", "myData");
UnityWebRequest www = UnityWebRequest.Post("http://www.my-server.com/myform", form);
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
Debug.Log("Form upload complete!");
}
}
}
To provide greater control over how you specify your form data, the UnityWebRequest
system contains a (user-implementable) IMultipartFormSection
interface. For standard applications, Unity also provides default implementations for data and file sections: MultipartFormDataSection
and MultipartFormFileSection
.
An overload of UnityWebRequest.POST
accepts, as a second parameter, a List argument, whose members must all be IMultipartFormSections
. The function signature is:
WebRequest.Post(string url, List<IMultipartFormSection> formSections);
This method creates a UnityWebRequest
and sets the target URL to the first string parameter. It also sets the Content-Type header of the UnityWebRequest
appropriately for the form data specified in the list of IMultipartFormSection
objects.
This method, by default, attaches a DownloadHandlerBuffer
to the UnityWebRequest
. This is for convenience: you can use this to check your server’s replies.
Similar to the WWWForm POST
method, this HLAPI method will call each supplied IMultipartFormSection
in turn and format them into a standard multipart form as specified in RFC 2616.
The preformatted form data will be stored in a standard UploadHandlerRaw
object, which is then attached to the UnityWebRequest
. As a result, changes to the IMultipartFormSection
objects performed after the UnityWebRequest.POST
call will not be reflected in the data sent to the server.
Пример:
using UnityEngine;
using System.Collections;
class MyBehavior: public 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("http://www.my-server.com/myform", formData);
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
Debug.Log("Form upload complete!");
}
}
}
Some modern web applications prefer that files be uploaded via the HTTP PUT verb. For this scenario, Unity provides the UnityWebRequest.PUT method.
This method takes two arguments. The first argument is a string and specifies the target URL for the request. The second argument may be either a string or a byte array, and specifies the payload data to be sent to the server.
Function signatures:
WebRequest.Put(string url, string data);
WebRequest.Put(string url, byte[] data);
This method creates aUnityWebRequest
and sets the content type to application/octet-stream
.
This method attaches a standard DownloadHandlerBuffer
to the UnityWebRequest
. As with the POST methods, you can use this to return result data from your applications.
This method stores the input upload data in a standard UploadHandlerRaw
object and attaches it to the UnityWebRequest
. As a result, if using the byte[] method, changes to the byte array performed after the UnityWebRequest.PUT
call will not be reflected in the uploaded data to the server.
Пример:
using UnityEngine;
using System.Collections;
class MyBehavior: public MonoBehaviour {
void Start() {
StartCoroutine(Upload());
}
IEnumerator Upload() {
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.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
Debug.Log("Upload complete!");
}
}
}
While the HLAPI is designed to minimize boilerplate code, the LLAPI is designed to permit maximum flexibility. In general, using the LLAPI involves creating UnityWebRequests, then creating appropriate DownloadHandlers
or UploadHandlers
and attaching them to your UnityWebRequests
.
For full details on each of the objects described in this section, please refer to the Scripting Reference.
Note: The HLAPI and LLAPI are not mutually exclusive. You can always customize UnityWebRequest objects created via the HLAPI if you need to tweak a common scenario.
WebRequests can be simply instantiated like any other object. Two constructors are available. The standard, parameterless constructor creates a new UnityWebRequest with all settings blank or default: * The target URL is not set * No custom headers are set * The redirect limit is set to 32
The second constructor takes a string argument. It assigns the UnityWebRequest’s target URL to the value of the string argument, and is otherwise identical to the parameterless constructor.
UnityWebRequest wr = new UnityWebRequest(); // Completely blank
UnityWebRequest wr2 = new UnityWebRequest("http://www.mysite.com"); // Target URL is set
Currently, only one type of upload handler is available: UploadHandlerRaw
. This class accepts a data buffer at construction time. This buffer is copied internally into native-code memory and then used by the UnityWebRequest
system when the remote server is ready to accept body data.
Upload Handlers also accept a Content Type string. This string will be used for the value of the UnityWebRequest’s Content-Type header if you set no Content-Type header on the UnityWebRequest itself. If you manually set a Content-Type header on the UnityWebRequest object, then the Content-Type on the Upload Handler object will be ignored.
If you do not set a Content-Type on either the UnityWebRequest or the UploadHandler
, then the system will default to setting a Content-Type of application/octet-stream
.
Пример:
byte[] payload = new byte[1024];
// ... fill payload with data ...
UnityWebRequest wr = new UnityWebRequest("http://www.mysite.com/data-upload");
UploadHandler uploader = new UploadHandlerRaw(payload);
// Will send header: "Content-Type: custom/content-type";
uploader.contentType = "custom/content-type";
wr.uploadHandler = uploader;
Currently, there are four types of DownloadHandlers
:
DownloadHandlerBuffer
stores received data in a native-code byte buffer, and permits access either to the raw bytes or will convert it into a UTF8 string.DownloadHandlerTexture
stores received data in a UnityEngine.Texture
. On download completion, it will decode JPEGs and PNGs into valid UnityEngine.Texture objects
. Only one copy of the UnityEngine.Texture
will be created per DownloadHandlerTexture
object, which will reduce performance hits from garbage collection.DownloadHandlerAssetBundle
streams received data into Unity’s asset bundle system. Once the asset bundle system has received enough data, the asset bundle will be available as a UnityEngine.AssetBundle
object. As above, only one copy of the UnityEngine.AssetBundle
object will be created to reduce memory impact.DownloadHandlerScript
is a special class. On its own, it will do nothing. However, this class can be inherited by a user-defined class. This class will receive callbacks from the UnityWebRequest system, which can then be used to perform completely custom handling of data as it arrives from the network.A specialized Download Handler for Audio Clips is also available. The APIs are analogous to DownloadHandlerTexture
’s interface.
This download handler is the simplest and handles the majority of use cases. It simply stores received data in a (native-code) buffer. When the download is complete, you may access the buffered data either as an array of bytes or as a UTF8 string.
Example:
using UnityEngine;
using System.Collections;
class MyBehaviour: public MonoBehaviour {
void Start() {
StartCoroutine(GetText());
}
IEnumerator GetText() {
UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
// Show results as text
Debug.Log(www.downloadHandler.text);
// Or retrieve results as binary data
byte[] results = www.downloadHandler.data;
}
}
}
While you could use a DownloadHandlerBuffer
to download an image file and then create a texture from the raw bytes using Texture.LoadImage
, it’s more efficient to use DownloadHandlerTexture
.
This download handler performs buffering, decompression and texture creation in native code. Further, decompression and texture creation are performed on a worker thread instead of the main thread, which can improve frame time when loading large textures.
Finally, DownloadHandlerTexture
only allocates managed memory when finally creating the Texture itself, which eliminates the garbage collection overhead associated with performing the byte-to-texture conversion in script.
The following example downloads a PNG from the internet, converts it to a Sprite and assigns it to a uGUI Image:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
[RequireComponent(typeof(UnityEngine.UI.Image))]
public class ImageDownloader : MonoBehaviour {
UnityEngine.UI.Image _img;
void Start () {
_img = GetComponent<UnityEngine.UI.Image>();
Download("http://www.mysite.com/myimage.png");
}
public void Download(string url) {
StartCoroutine(LoadFromWeb(url));
}
IEnumerator LoadFromWeb(string url)
{
UnityWebRequest wr = new UnityWebRequest(url);
DownloadHandlerTexture texDl = new DownloadHandlerTexture(true);
wr.downloadHandler = texDl;
yield return wr.Send();
if(!wr.isError) {
Texture2D t = texDl.texture;
Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),
Vector2.zero, 1f);
_img.sprite = s;
}
}
}
The advantage to this specialized download handler is that it is capable of streaming data to Unity’s asset bundle system. This considerably reduces runtime memory allocation, as well as the memory impact of loading your asset bundles. Further, it allows asset bundles to be partially used while not fully downloaded - that is, you can stream assets.
All downloading and decompression occurs on worker threads.
Asset Bundles are downloaded via a DownloadHandlerAssetBundle
object, which has a special assetBundle
property to retrieve the asset bundle.
Due to the way the Asset Bundle system works, all asset bundles must have an address associated with them. Generally, this is the nominal URL at which they’re located (i.e. the URL prior to redirects). In almost all cases, you should simply pass in the same URL as you passed to the UnityWebRequest. When using the HLAPI, this is done for you.
Пример:
using UnityEngine;
using System.Collections;
class MyBehaviour: public MonoBehaviour {
void Start() {
StartCoroutine(GetAssetBundle());
}
IEnumerator GetAssetBundle() {
UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url);
www.downloadHandler = handler;
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
// Extracts asset bundle
AssetBundle bundle = handler.assetBundle;
}
}
}
For power users who require full control over the processing of downloaded data, Unity provides the DownloadHandlerScript
class.
By default, instances of this class will do nothing. However, if you derive your own classes from DownloadHandlerScript
, you may override certain methods and use them to receive callbacks as data arrives from the network.
Note: Even though the actual downloads occur on a worker thread, all DownloadHandlerScript
callbacks operate on the main thread. Avoid performing computationally-heavy operations during these callbacks.
protected void ReceiveContentLength(long contentLength);
This method is called when the Content-Length header is received.
Note: This callback may occur multiple times if your server issues one or more redirect responses over the course of processing your UnityWebRequest.
protected void OnContentComplete();
This method is called when the UnityWebRequest has fully downloaded all data from the server, and has forwarded all received data to the ReceiveData callback.
protected bool ReceiveData(byte[] data, long dataLength);
This method is called after data has arrived from the remote server. This method will be called once per frame. The data argument contains the raw bytes received from the remote server, and dataLength indicates the length of new data in the data array.
When not using pre-allocated data buffers, the system will create a new byte array each time it calls this callback, and dataLength will always be equal to data.Length
. When using pre-allocated data buffers, the data buffer will be reused and dataLength
must be used to find the number of updated bytes.
This method requires a return value of either true or false. If you return false, the system will immediately abort the UnityWebRequest. If you return true, processing will continue normally.
Many of Unity’s power users are constantly concerned with reducing CPU spikes due to garbage collection. For these users, the UnityWebRequest system permits the pre-allocation of a managed-code byte array which will be used to deliver downloaded data to DownloadHandlerScript’s ReceiveData
callback.
Using this method completely eliminates managed-code memory allocation when using DownloadHandlerScript-derived classes to capture downloaded data.
To make a DownloadHandlerScript
operate with a pre-allocated managed buffer, simply supply a byte array to the constructor of DownloadHandlerScript
.
Note: The size of the byte array limits the amount of data delivered to the ReceiveData callback each frame. Do not provide too small of a byte array or your data will arrive slowly, over many frames.
Пример
using UnityEngine;
using System.Collections;
public class LoggingDownloadHandler : DownloadHandlerScript {
// Standard scripted download handler - will allocate memory on each ReceiveData callback
public LoggingDownloadHandler(): base() {
}
// Pre-allocated scripted download handler
// Will reuse the supplied byte array to deliver data.
// Eliminates memory allocation.
public LoggingDownloadHandler(byte[] buffer): base(buffer) {
}
// Required by DownloadHandler base class. Called when you address the 'bytes' property.
protected override byte[] GetData() { return null; }
// Called once per frame when data has been received from the network.
protected override bool ReceiveData(byte[] data, int dataLength) {
if(data == null || data.Length < 1) {
Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer");
return false;
}
Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength));
return true;
}
// Called when all data has been received from the server and delivered via ReceiveData
protected override void CompleteContent() {
Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");
}
// Called when a Content-Length header is received from the server.
protected override void ReceiveContentLength(int contentLength) {
Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
}
}