📁

UnityStandaloneFileBrowserを使ってみた

2022/08/31に公開

Unityでファイル選択ダイアログを使う必要があり、方法を調べていたところ以下2つの方法が見つかりました。(他にもあるかもしれませんが、筆者が調べた範囲で見つかったものは以下でした)

OpenFileDialogは.NETのクラスなので、Windowsビルド向けにしか利用できない模様。今回は、WebGLビルドで利用したかったため、UnityStandaloneFileBrowserを試すことにしました。
UnityStandaloneFileBrowserは、各OS(Windows,Mac,Linux )ビルド、WebGLビルドに対応しているようです。

サンプルアプリの作成

本記事執筆時における環境情報は以下です。

  • OS: macOS Monterey バージョン12.5.1
  • Unity Editor: バージョン2021.3.5f

なお、今回作成したサンプルアプリは以下に置いています。
https://github.com/plumchang/UnityStandaloneFileBrowser_webgl_sample

UnityStandaloneFileBrowserの導入

  1. UnityStandaloneFileBrowserのGithubページのDownload Packageより、StandaloneFileBrowser.unitypackageをダウンロードします。

  2. ダウンロードしたStandaloneFileBrowser.unitypackageをUnityプロジェクトのプロジェクトウィンドウのドラッグ&ドロップして、インポートします。

コンソールにエラーが出てましたが、一旦無視します。

GameObjectの配置

Canvasとその下にPanelを作成。さらにその下にLoadSaveのボタン、テキスト出力用のテキストを作成しています。配置は適当です。

スクリプト作成

Assetsフォルダの下にScriptsフォルダを作成。
Scripts配下に、FileLoadSample.csFileSaveSample.csの2つのファイルを作成します。

FileLoadSample.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SFB;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityEngine.EventSystems;

[RequireComponent(typeof(Button))]
public class FileLoadSample : MonoBehaviour, IPointerDownHandler
{
    // テキストアウトプット
    [SerializeField] private Text outputText;

    // 読み込んだテキスト
    private string _loadedText = "";

#if UNITY_WEBGL && !UNITY_EDITOR
    //
    // WebGL
    //

    // StandaloneFileBrowserのブラウザスクリプトプラグインから呼び出す
    [DllImport("__Internal")]
    private static extern void UploadFile(string gameObjectName, string methodName, string filter, bool multiple);

    // ファイルを開く
    public void OnPointerDown(PointerEventData eventData) {
        UploadFile(gameObject.name, "OnFileUpload", ".", false);
    }

    // ファイルアップロード後の処理
    public void OnFileUpload(string url) {
        StartCoroutine(Load(url));
    }

#else
    //
    // OSビルド & Unity editor上
    //
    public void OnPointerDown(PointerEventData eventData) { }

    void Start()
    {
        var button = GetComponent<Button>();
        button.onClick.AddListener(() => OpenFile());
    }

    // ファイルを開く
    public void OpenFile()
    {
        // 拡張子フィルタ
        var extensions = new[] {
            new ExtensionFilter("All Files", "*" ),
        };

        // ファイルダイアログを開く
        var paths = StandaloneFileBrowser.OpenFilePanel("Open File", "", extensions, false);
        if (paths.Length > 0 && paths[0].Length > 0)
        {

            StartCoroutine(Load(new System.Uri(paths[0]).AbsoluteUri));

        }
    }

#endif
    // ファイル読み込み
    private IEnumerator Load(string url)
    {
        var request = UnityWebRequest.Get(url);

        var operation = request.SendWebRequest();
        while (!operation.isDone)
        {
            yield return null;
        }

        _loadedText = request.downloadHandler.text;
        Debug.Log(_loadedText);
        outputText.text = _loadedText;
    }

}
FileSaveSample.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SFB;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityEngine.EventSystems;

[RequireComponent(typeof(Button))]
public class FileSaveSample : MonoBehaviour, IPointerDownHandler
{
    // テキストアウトプット
    [SerializeField] private Text outputText;

#if UNITY_WEBGL && !UNITY_EDITOR
    //
    // WebGL
    //

    // StandaloneFileBrowserのブラウザスクリプトプラグインから呼び出す
    [DllImport("__Internal")]
    private static extern void DownloadFile(string gameObjectName, string methodName, string filename, byte[] byteArray, int byteArraySize);

    // ファイルを保存する
    public void OnPointerDown(PointerEventData eventData) {
        var str = outputText.text + "_saved";

        if (str.Length > 0)
        {
            var bytes = Encoding.UTF8.GetBytes(str);
            DownloadFile(gameObject.name, "OnFileDownload", "sample_saved.txt", bytes, bytes.Length);
        }
    }

    // ファイルダウンロード後の処理
    public void OnFileDownload() {
        Debug.Log("CSV file saved");
        outputText.text = "File Saved";
    }

#else

    //
    // OSビルド & Unity editor上
    //

    public void OnPointerDown(PointerEventData eventData) { }

    void Start()
    {
        var button = GetComponent<Button>();
        button.onClick.AddListener(() => SaveFile());
    }

    // ファイルを保存する
    public void SaveFile()
    {
        var str = outputText.text + "_saved";

        if (str.Length > 0)
        {
            var path = StandaloneFileBrowser.SaveFilePanel("ファイルの保存", "", "sample_saved", "txt");
            if (!string.IsNullOrEmpty(path))
            {
                File.WriteAllText(path, str);
                Debug.Log("File saved");
                outputText.text = "File Saved";
            }
        }
    }

#endif

}

FileLoadSample.csLoadButtonに、FileSaveSample.csSaveButtonにアタッチします。インスペクタビューより、Outputテキストへの参照を渡します。

エディタ上でデバッグ実行してみます。
まずはロードです。Loadボタンを押すと、ファイル選択ダイアログが開きます。

ファイルを開くと、色々エラーは出たままですが、とりあえず出力用テキストとコンソールにファイル内容が出力されます。

次にセーブです。Saveボタンを押すと、ファイル保存のダイアログが開きます。

保存されたファイルを開くと、先ほど開いたファイル内容に_savedが追記されて保存されました。

WebGLビルド

[Build Settings...]→[WebGL]を開き、Switch Platformをクリックします。

しばらく待つと完了しますが、Buildが押せない状態になっています。

[Player Settings]を開き、[Player]→[Other Settings]を確認すると、Color SpaceLightmap Encodingに注意書きが出ています。

それぞれ、GammaNormal Qualityに変更します。

ビルドができるようになったので、Build And Runをクリックします。
保存先は適当に指定。ビルドには数分かかります。

動作確認

ビルドが終わると、ブラウザが自動的に開きます。
ボタンサイズがかなり小さくなってしまいましたが。。とりあえず起動しました。

WebGL後も、Loadボタンを押すと問題なくファイル選択ダイアログが開きます。

Saveボタンも問題ありませんでした。

以上、UnityStandaloneFileBrowserを使ってファイル選択ダイアログを利用することができました。
細かい挙動についてはまだ理解しきれていないので、色々試しながら理解していきたいところです。

参考にさせていただいた記事

Discussion