참고: UNet은 지원이 중단되었으며 향후 삭제될 예정입니다. 현재 새로운 시스템이 개발 중입니다. 자세한 내용과 다음 단계는 이 블로그 포스트와 FAQ를 참조하십시오.
다음과 같은 몇 가지 DownloadHandler
타입이 있습니다.
DownloadHandlerBuffer
는 단순 데이터 스토리지로 사용됩니다.DownloadHandlerFile
은 메모리를 적게 사용하면서 파일을 다운로드하고 디스크에 저장하는 데 사용됩니다.DownloadHandlerTexture
는 이미지를 다운로드하는 데 사용됩니다.DownloadHandlerAssetBundle
은 에셋 번들을 가져오는 데 사용됩니다.DownloadHandlerAudioClip
은 오디오 파일을 다운로드하는 데 사용됩니다.DownloadHandlerMovieTexture
는 비디오 파일을 다운로드하는 데 사용됩니다. MovieTexture는 지원이 중단되었으므로 비디오를 다운로드하고 재생하려면 VideoPlayer를 사용하는 것이 좋습니다.DownloadHandlerScript
는 특별한 클래스입니다. 자체적으로는 아무 역할도 하지 않지만, 이 클래스는 사용자가 정의한 클래스에 의해 상속될 수 있습니다. 이 클래스는 UnityWebRequest 시스템에서 콜백을 수신하며, 이 콜백은 네트워크에서 도착한 데이터를 완전히 커스터마이즈하여 처리하는 데 사용할 수 있습니다.API는 DownloadHandlerTexture
의 인터페이스와 유사합니다.
UnityWebRequest
에는 기본값이 true인 disposeDownloadHandlerOnDispose
프로퍼티가 있습니다. 이 프로퍼티가 true인 경우 UnityWebRequest 오브젝트가 폐기되면 연결된 다운로드 핸들러에서 Dispose()도 호출되어 오브젝트가 쓸모없게 됩니다. 다운로드 핸들러에 대한 레퍼런스를 UnityWebRequest에 대한 레퍼런스보다 더 오래 유지하는 경우 disposeDownloadHandlerOnDispose를 false로 설정해야 합니다.
이 다운로드 핸들러는 가장 단순하고, 대부분의 사용 사례를 처리합니다. 이 다운로드 핸들러는 수신한 데이터를 네이티브 코드 버퍼에 저장합니다. 다운로드가 완료되면 바이트 배열 또는 텍스트 문자열로 버퍼링된 데이터에 액세스할 수 있습니다.
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class MyBehaviour : MonoBehaviour {
void Start() {
StartCoroutine(GetText());
}
IEnumerator GetText() {
UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) {
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;
}
}
}
큰 파일에 사용하는 특수 다운로드 핸들러입니다. 다운로드된 바이트를 파일에 직접 쓰므로 다운로드하는 파일 크기에 관계없이 메모리 사용량이 적습니다. 다른 다운로드 핸들러와의 차이점은 모든 데이터가 파일에 저장되므로 데이터를 꺼낼 수 없다는 데 있습니다.
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
public class FileDownloader : MonoBehaviour {
void Start () {
StartCoroutine(DownloadFile());
}
IEnumerator DownloadFile() {
var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);
string path = Path.Combine(Application.persistentDataPath, "unity3d.html");
uwr.downloadHandler = new DownloadHandlerFile(path);
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
Debug.LogError(uwr.error);
else
Debug.Log("File successfully downloaded and saved to " + path);
}
}
DownloadHandlerBuffer
를 사용하여 이미지 파일을 다운로드한 다음 Texture.LoadImage
를 사용하여 원시 바이트에서 텍스처를 생성하는 대신 DownloadHandlerTexture
를 사용하는 것이 더 효율적입니다.
이 다운로드 핸들러는 수신한 데이터를 UnityEngine.Texture
에 저장합니다. 다운로드가 완료되면 JPEG와 PNG를 유효한 UnityEngine.Texture 오브젝트
로 디코드합니다. DownloadHandlerTexture
오브젝트마다 UnityEngine.Texture
복사본이 하나씩만 생성됩니다. 따라서 가비지 컬렉션으로 인한 성능 저하가 완화됩니다. 핸들러는 네이티브 코드로 버퍼링, 압축 풀기, 텍스처 생성을 수행합니다. 또한 압축 풀기 및 텍스처 생성은 메인 스레드 대신 워커 스레드에서 수행되므로 큰 텍스처를 로드할 때 프레임 시간이 개선됩니다.
마지막으로, DownloadHandlerTexture
는 텍스처 자체를 최종적으로 생성할 때만 관리되는 메모리를 할당하므로 스크립트에서 바이트를 텍스처로 변환하는 것과 관련된 가비지 컬렉션 오버헤드가 제거됩니다.
다음 예제에서는 인터넷에서 PNG를 다운로드하여 스프라이트로 변환하고 이미지에 할당합니다.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
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.SendWebRequest();
if(!(wr.isNetworkError || wr.isHttpError)) {
Texture2D t = texDl.texture;
Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),
Vector2.zero, 1f);
_img.sprite = s;
}
}
}
이 특화된 다운로드 핸들러의 장점은 데이터를 Unity 에디터의 에셋 번들 시스템에 스트리밍할 수 있다는 것입니다. 에셋 번들 시스템에 데이터가 충분히 수신되면 에셋 번들을 UnityEngine.AssetBundle
오브젝트로 사용할 수 있습니다. UnityEngine.AssetBundle
오브젝트 복사본 하나만 생성됩니다. 따라서 런타임 메모리 할당 및 에셋 번들 로드의 메모리 영향이 상당히 감소합니다. 또한 에셋 번들을 완전히 다운로드하지 않은 상태에서 부분적으로 사용할 수 있으므로 에셋도 스트리밍할 수 있습니다.
모든 다운로드와 압축 풀기는 워커 스레드에서 수행됩니다.
에셋 번들을 검색해서 가져오는 특수 assetBundle
프로퍼티가 있는 DownloadHandlerAssetBundle
오브젝트를 통해 에셋 번들이 다운로드됩니다.
에셋 번들 시스템의 작동 방식으로 인해 모든 에셋 번들에는 연결된 주소가 있어야 합니다. 일반적으로 이 주소는 에셋 번들이 있는 위치의 명목 URL(리디렉션하기 전의 URL을 의미)입니다. 거의 모든 경우 UnityWebRequest에 전달한 URL과 동일한 URL을 전달해야 합니다. 이 작업은 고수준 API(HLAPI)를 사용할 경우 자동으로 완료됩니다.
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class MyBehaviour : MonoBehaviour {
void Start() {
StartCoroutine(GetAssetBundle());
}
IEnumerator GetAssetBundle() {
UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url, uint.MaxValue);
www.downloadHandler = handler;
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) {
Debug.Log(www.error);
}
else {
// Extracts AssetBundle
AssetBundle bundle = handler.assetBundle;
}
}
}
이 다운로드 핸들러는 오디오 파일을 다운로드하는 데 최적화되었습니다. DownloadHandlerBuffer
를 사용하여 원시 바이트를 다운로드한 다음 이를 사용하여 AudioClip
을 생성하는 대신 이 다운로드 핸들러를 사용하여 더 편리한 방법으로 생성할 수 있습니다.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class AudioDownloader : MonoBehaviour {
void Start () {
StartCoroutine(GetAudioClip());
}
IEnumerator GetAudioClip() {
using (var uwr = UnityWebRequestMultimedia.GetAudioClip("http://myserver.com/mysound.ogg", AudioType.OGGVORBIS)) {
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError) {
Debug.LogError(uwr.error);
yield break;
}
AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
// use audio clip
}
}
}
참고: MovieTexture는 지원이 중단될 예정입니다. 비디오를 다운로드하고 재생하려면 VideoPlayer를 사용해야 합니다.
이 다운로드 핸들러는 비디오 파일을 다운로드하는 데 최적화되었습니다. DownloadHandlerBuffer
를 사용하여 원시 바이트를 다운로드한 다음 이를 사용하여 MovieTexture
을 생성하는 대신 이 다운로드 핸들러를 사용하여 더 편리한 방법으로 생성할 수 있습니다.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class MovieDownloader : MonoBehaviour {
void Start () {
StartCoroutine(GetAudioClip());
}
IEnumerator GetAudioClip() {
using (var uwr = UnityWebRequestMultimedia.GetMovieTexture("http://myserver.com/mysound.ogg")) {
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError) {
Debug.LogError(uwr.error);
yield break;
}
MovieTexture movie = DownloadHandlerMovieTexture.GetContent(uwr);
// use movie texture
}
}
}
다운로드된 데이터의 처리를 완전히 관리해야 하는 사용자를 위해, Unity 에디터는 DownloadHandlerScript
클래스를 제공합니다.
기본적으로 이 클래스의 인스턴스는 아무것도 하지 않습니다. 하지만 DownloadHandlerScript
에서 자체 클래스를 가져오는 경우 특정 함수를 오버라이드하고 이를 사용하여 데이터가 네트워크에서 도착할 때 콜백을 수신할 수 있습니다.
참고: 실제 다운로드는 워커 스레드에서 발생하지만 모든 DownloadHandlerScript
콜백은 메인 스레드에서 작동합니다. 이 콜백 중에 연산 처리가 많은 작업은 피해야 합니다.
protected void ReceiveContentLength(long contentLength);
이 함수는 Content Length 헤더가 수신될 때 호출됩니다. UnityWebRequest를 처리하는 과정 중에 서버에서 하나 이상의 리디렉션 응답을 전송하는 경우 이 콜백이 여러 번 발생할 수 있습니다.
protected void OnContentComplete();
이 함수는 UnityWebRequest가 서버에서 모든 데이터를 완전히 다운로드한 후 수신된 모든 데이터를 ReceiveData 콜백에 전달했을 때 호출됩니다.
protected bool ReceiveData(byte[] data, long dataLength);
이 함수는 원격 서버에서 데이터가 도착했을 때 프레임당 한 번씩 호출됩니다. data
인수에는 원격 서버에서 수신한 원시 바이트가 포함되며, dataLength
는 데이터 배열에서 새 데이터의 길이를 나타냅니다.
미리 할당된 데이터 버퍼를 사용하지 않는 경우 이 콜백을 호출할 때마다 시스템에서 새 바이트 배열을 생성하며, dataLength
는 항상 data.Length
와 같습니다. 미리 할당된 데이터 버퍼를 사용하는 경우 데이터 버퍼가 재사용되고, 업데이트된 바이트의 수를 찾으려면 dataLength
를 사용해야 합니다.
이 함수에는 true 또는 false 인 반환 값이 필요합니다. false 를 반환하면 시스템이 즉시 UnityWebRequest를 중단하고, true 를 반환하면 정상적으로 처리가 계속됩니다.
Unity 에디터의 고급 사용자는 대부분 가비지 컬렉션 때문에 발생하는 CPU 점유율이 치솟는 현상(CPU spike)를 줄이는 데 관심이 있습니다. 이러한 사용자를 위해 UnityWebRequest 시스템은 관리된 코드 바이트 배열을 사전 할당을 허용하며, 이 바이트 배열은 다운로드한 데이터를 DownloadHandlerScript의 ReceiveData
콜백에 전달하는 데 사용됩니다.
이 함수를 사용하면 다운로드한 데이터를 캡처하기 위해 DownloadHandlerScript에서 파생된 클래스를 사용할 때 관리되는 코드 메모리 할당을 완전히 제거할 수 있습니다.
DownloadHandlerScript
를 미리 할당된 관리 버퍼와 함께 사용하려면 바이트 배열을 DownloadHandlerScript
의 생성자에 공급해야 합니다.
참고: 바이트 배열의 크기에 따라 프레임마다 ReceiveData 콜백에 전달되는 데이터의 양이 제한됩니다. 너무 작은 바이트 배열을 제공하면 여러 프레임에 걸쳐 데이터가 늦게 도착할 수 있습니다.
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class LoggingDownloadHandler : DownloadHandlerScript {
// Standard scripted download handler - allocates memory on each ReceiveData callback
public LoggingDownloadHandler(): base() {
}
// Pre-allocated scripted download handler
// reuses 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));
}
}