MRが楽しい

MRやVRについて学習したことを書き残す

HttpClientを使ってUnityでインターネット上のファイルをダウンロードする

本日は .Net の小ネタ枠です。
HttpClientを使ってUnityでインターネット上のファイルをダウンロードする方法を記事にします。
f:id:bluebirdofoz:20210620231300j:plain

HttpClient

.Net で提供されている URL から HTTP 応答を受信するためのクラスです。
docs.microsoft.com

実装例

指定のURLからStreamingAssetsフォルダにファイルをダウンロードするサンプルスクリプトを作成しました。
・HttpGet.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using System;
using System.IO;
// HttpClient利用のため
using System.Net;
using System.Net.Http;

public class HttpGet : MonoBehaviour
{
    /// <summary>
    /// ダウンロード完了時イベント
    /// </summary>
    public Action<string> GetComplete;

    /// <summary>
    /// ダウンロード失敗時イベント
    /// </summary>
    public Action GetFailed;

    /// <summary>
    /// 指定URLのファイルをダウンロードする
    /// </summary>
    /// <param name="url"></param>
    public async void AsyncHttpGet(string url)
    {
        // URL文字列からURIが作成可能か
        Uri uriResult;
        if (!Uri.TryCreate(url, UriKind.Absolute, out uriResult))
        {
            // URIが作成できなければ失敗
            GetFailed?.Invoke();
            return;
        }

        // URL文字列からファイル名を取得する
        string fileName = Path.GetFileName(url);

        // HTTP GET のリクエストメッセージを作成する
        HttpClient httpClient = new HttpClient();
        HttpRequestMessage request = new HttpRequestMessage
        {
            Method = HttpMethod.Get,
            RequestUri = uriResult
        };

        // リクエストの実行
        HttpResponseMessage response = await httpClient.SendAsync(request);

        if (response.StatusCode == HttpStatusCode.OK)
        {
            // レスポンスコードが成功(200)の場合
            // バイト配列をファイルとして書き出す
            byte[] contentByteData = await response.Content.ReadAsByteArrayAsync();
            string saveFilePath = GetSaveFilePath(fileName);
            File.WriteAllBytes(saveFilePath, contentByteData);

            // ダウンロード完了イベントを実行
            GetComplete?.Invoke(saveFilePath);
        }
        else
        {
            // レスポンスコードが成功以外の場合
            Debug.LogError("HttpGet Error : " + response.StatusCode);
            // ダウンロード失敗イベントを実行
            GetFailed?.Invoke();
        }
    }

    /// <summary>
    /// 保存先のファイルパスを生成する
    /// </summary>
    /// <param name="filename"></param>
    /// <returns></returns>
    private string GetSaveFilePath(string filename)
    {
        // ディレクトリの保存先を指定する
#if WINDOWS_UWP
        // HoloLens上での動作の場合、LocalAppData/AppName/LocalStateフォルダを参照する
        string directory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#else
        // Unity上での動作の場合、Assets/StreamingAssetsフォルダを参照する
        string directory = UnityEngine.Application.streamingAssetsPath;
#endif
        return Path.Combine(directory, filename);
    }
}

シーンの適当なオブジェクトにスクリプトを設定します。
f:id:bluebirdofoz:20210620231324j:plain

更に本スクリプトを Editor 上からも直接実行可能なように以下の HttpGet のエディター拡張スクリプトを作成しました。
・HttpGetEditor.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;

// 拡張するクラスを指定する
[CustomEditor(typeof(HttpGet))]
public class HttpGetEditor : Editor
{
    private string inputText;

    // GUIの表示関数をオーバーライドする
    public override void OnInspectorGUI()
    {
        // 元のインスペクター部分を表示
        base.OnInspectorGUI();

        // targetを変換して対象スクリプトの参照を取得する
        HttpGet targetScript = target as HttpGet;

        // public関数を実行するボタンの作成
        if (GUILayout.Button("AsyncHttpGetの実行"))
        {
            targetScript.AsyncHttpGet(inputText);
        }

        inputText = EditorGUILayout.TextField("URL", inputText);
    }
}
#endif

スクリプトを作成すると、以下の通り、HttpGet の Inspector にURLの入力欄と関数の実行ボタンが追加されます。
f:id:bluebirdofoz:20210620231336j:plain

動作確認

エディター上で動作確認を行います。
Assets フォルダに StreamingAssets フォルダを作成し、シーンを再生します。
f:id:bluebirdofoz:20210620231348j:plain

URLに以下のサンプル GLB ファイルのアドレスを指定し、関数の実行ボタンをクリックします。

https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb

f:id:bluebirdofoz:20210620231400j:plain

成功すると、StreamingAssets フォルダにファイルがダウンロードされます。
f:id:bluebirdofoz:20210620231410j:plain