WebGLビルドのStreamingAssetsのパスが変更できず困っているの…
公式で変更手段が提供されているわ。状況によっては少し特殊な方法を使わないといけないけど可能だわ。
UnityのWebGLビルドでは、初期設定ではアセットバンドル等で使用されるStreamingAssetsフォルダのパスは、ゲームの公開URL直下のStreamingAssetsパスに設定されています。
StreamingAssetsパスの例
参考:Unity – Manual: Streaming Assets
このURLは、Application.streamingAssetsPathが返す結果と一緒です。
参考:Unity – Scripting API: Application.streamingAssetsPath
WebGLビルドにおけるStreamingAssetsのパスの変更手段は、ビルドして出力されるページのファイル(index.html)を編集する方法として公式で提供されています。
参考:Unity – Manual: WebGL templates
しかし、unityroomで公開するゲームでStreamingAssetsを使用したい場合など、index.htmlの編集以外の方法でパス変更したい場合、ハック的な方法ですが次の代替手段で書き換え可能です。
- ビルド後に.loader.jsファイルを書き換える
- jslibで動的にパスを変更する処理を実装する
本記事では、これら3種類のWebGLビルドにおけるStreamingAssetsのパスを書き換える方法を解説していきます。
- Unity 2023.3.20f1
目次 非表示
想定する状況
次のようなURLでゲームを公開しているものとします。
この時、StreamingAssetsのパスはデフォルトでは次のようになっています。
このStreamingAssetsパスを次のような別ドメインなどのパスに変更することを想定します。
変更後のパスは同ドメインであっても問題ありません。
本記事では、UnityプロジェクトのビルドのターゲットプラットフォームがWebGLになっていることを前提で手順を進めます。また、変更結果の確認はコンソールログ経由で行うものとします。
参考:Unity – Manual: Build Settings
index.htmlを書き換える(静的)
1つ目の方法は、Unityが紹介している公式の手順です。特別な理由がない限りはこの方法を推奨します。
WebGLビルドすると、ビルドフォルダにはゲームの公開ページ用のindex.htmlファイルが生成されます。
このindex.htmlファイル内のstreamingAssetsUrlに指定している文字列を変更することで、StreamingAssetsのパスをデフォルトから変更できます。
これは、Unityコンテンツのインスタンス生成関数createUnityInstanceの引数に渡すconfigオブジェクトのフィールドでconfig.streamingAssetsUrlフィールドがそのままStreamingAssetsパスのURLとして設定されます。
参考:Unity – Manual: WebGL templates
ビルド後のindex.htmlを直接手で書き換えても良いですが、本記事ではカスタムテンプレートを作成して適用するものとして解説します。
WebGLTemplateの準備
index.htmlファイル等のテンプレートは、カスタムのものを適用できます。[Unityプロジェクトフォルダ]/Assets/WebGLTemplates/の下にテンプレートを置き、それをPlayer settingsから適用すれば良いです。
本記事では、既存のDefaultテンプレートを流用するものとします。
まず、対象のUnityアプリケーションフォルダに格納されている以下フォルダを複製します。
コピー元
コピー先
「Custom」の部分はお好みの名前で問題ありません。
作成したカスタムテンプレートを適用するために、トップメニューよりEdit > Project Settings…の順に選択してProject Settingsウィンドウを開きます。左側のツリーよりPlayerを選択し、Resolution and Presentation > WebGL Templateよりカスタムテンプレートを選択してください。
index.htmlの書き換え
次に、カスタムテンプレートフォルダ配下のindex.htmlの内容を書き換えます。
テキストエディタ等でファイルを開き、以下行をURLまたは相対パスに書き換えてください。
変更前
変更後の例
例えばURL形式ないパスを指定した場合、公開ページを基準とした相対パスとして扱われます。
確認用スクリプト
本記事では、正しくStreamingAssetsのパスが変更されているかをコンソールログから確認するものとします。
以下、StreamingAssetsのパスをログ出力するだけのスクリプトです。
上記をPrintPathExample.csという名前でUnityプロジェクトに保存し、ビルド対象シーンに適当なゲームオブジェクトを配置してアタッチしてください。
例では、起動直後に空シーンを読み込み、この中で表示するものとします。
実行結果
ログ出力されるStreamingAssetsのパスがデフォルトのものから変更されていることが確認できました。
.loader.jsの中身を書き換える(静的)
2つ目は、ビルド後に生成される.loader.jsファイルの中身を書き換える方法です。index.htmlを直接書き換えられない場合の代替候補の一つになります。
ここから先は正式には提供されていないハック的な方法になるためご注意ください。
index.html内で初期化時に呼び出されるcreateUnityInstance関数は、[ビルド出力フォルダ]/Build/[名前].loader.jsというJSファイル内で定義されています。
StreamingAssetsパスは、この関数が生成するunityInstanceオブジェクトのModule.streamingAssetsUrlフィールドに格納されています。
このフィールド値が最終的に希望のパスに書き換わるように.loader.jsファイル内をビルド後に書き換えれば良いです。
createUnityInstance関数内部では、
- Module.streamingAssetsUrlを「StreamingAssets」という文字列で初期化
- config.streamingAssetsUrlでパス指定されていればそれで上書き
- Module.streamingAssetsUrlをURLとして正規化
という流れでStreamingAssetsのパスが決定される処理になっているようです。
生成される.loader.jsファイルは、UnityアプリケーションフォルダにあるUnityLoader.jsファイルを処理して最小化したものです。
内部実装を確認したい場合は、上記を覗いてみると良いでしょう。
なお、.loader.jsのソースコード解析および実装にあたっては、以下記事を参考にさせていただきました。
書き換えスクリプトの実装
ビルド後の.loader.jsファイルのStreamingAssetsパスを書き換えるためのスクリプトを実装します。
本記事では、IPostprocessBuildWithReportインタフェースを通じてビルド終了時に.loader.jsファイル内の文字列置換を行うこととします。
参考:Unity – Scripting API: IPostprocessBuildWithReport
.loader.jsファイル内には、次のような文字列があるため、ここをカスタムURLに置き換えます。
上記コードの「m」の部分は「Module」という名前の変数が最小化(Minify)されたものであるため、Unityバージョンや環境によっては違う名前になる可能性があります。これに注意して文字列置換を行っていきます。
実装例
以下、ビルド後に生成された.loader.jsファイル内のStreamingAssetsパスを置換するスクリプトの実装例です。
簡単のため、例ではハードコードでURLを指定していますが、実際にはScriptableObjectやシンボル定義など、外部に設定を持たせることをお勧めします。
上記をStreamingAssetsPathPostProcessor.csという名前でUnityプロジェクトに保存しておきます。
後はこのままビルドすれば、ビルド終了時に置換処理が走ります。
実行結果
1つ目の例同様にStreamingAssetsパスが変わっていることが確認できました。
また、.loader.jsファイル内の該当箇所も独自パスに変化しています。
スクリプトの説明
ビルド終了後のタイミングは、IPostprocessBuildWithReportインタフェースを通じて取得できます。したがって、クラスにIPostprocessBuildWithReportを実装すれば良いです。
参考:Unity – Scripting API: IPostprocessBuildWithReport
例では、以下constフィールドに変更後のStreamingAssetsパスを定義しています。
.loader.jsファイルのフォルダは、[ビルド生成フォルダ]/Buildの直下に生成されるため、そのファイルを探します。
そして、テキストファイルとして内容をそのまま読み込みます。
文字列置換は、変数名が変わることに注意して、正規表現を用いて行うようにしています。
正規表現による置換を行った後は、ファイル内容を再び.loader.jsに適用(書き込み)して終了です。
実行時にパスを書き換える(動的)
2つ目の方法では、unityInstance.Module.streamingAssetsUrlの内容をビルドの最後で書き換えていました。
これはjslibプラグインを通じて実行時に書き換えることも可能です。例えば、実行時にAPIサーバー等からパスを受け取って動的に振り分けたいケースなどで活躍できるでしょう。
3つ目の方法では、jslibプラグインを実装してunityInstance.Module.streamingAssetsUrlを動的に書き換える方法を紹介します。
当方法もハック的な手法になります。また、動的にパスを書き換える性質上、書き換え前にApplication.streamingAssetsPathにアクセスしてしまわないように処理順に注意するといった対策が必要になるかもしれません。
.jslibファイルの実装
StreamingAssetsパスを書き換えるためのjslibプラグインを実装します。
以下、SetStreamingAssetsPathという名前の関数を定義した例です。
上記をSetStreamingAssetsPath.jslibなどという名前で、Pulgins配下の階層に保存してください。
例では、/Assets/Plugins/WebGL/直下に置くものとしました。
参考:Unity – Manual: Call JavaScript functions from Unity C# scripts
参考:Unity – Manual: Import and configure plug-ins
C#スクリプトでの使用例
前述の.jslibで実装したSetStreamingAssetsPath関数をC#スクリプト側から呼び出して実行してパス書き換えを実現します。
以下、初期化時に書き換えてログ出力する例です。
上記をSetPathAtRuntimeExample.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチしてください。
前の例のPrintPathExample.csがアタッチされていれば、それを無効化するか削除しておきます。
実行結果
これまでの例と同様にパスが書き換えられていることが確認できました。
なお、上記書き換え後の結果は、.loader.jsのパスがデフォルトのまま(または別パスになっている)状態でも上書きされて適用されます。
スクリプトの説明
実際にStreamingAssetsパスを書き換える処理は以下部分です。
C#スクリプトから渡される文字列はそのままでは使えず、UTF8ToStringヘルパー関数でJavaScript用の文字列に変換する必要があります。
参考:Interaction with browser scripting – Unity マニュアル
jslibプラグインから実行される関数はunityInstanceスコープとなっているため、unityInstance.Module.streamingAssetsUrlフィールドにアクセスしたい場合はModule.streamingAssetsUrlとすれば良いです。
C#スクリプト側では、WebGLビルドとそうでない場合で分岐させています。
jslibの関数を使用するためには、[DllImport(“__Internal”)]属性を付加します。
参考:Unity – Manual: Call JavaScript functions from Unity C# scripts
別ドメインのパスに変更する際の注意点
本記事の例のように、異なるドメインのStreamingAssetsパスを設定する場合、変更先のサーバーでオリジン間リソース共有 (CORS)の設定が必要になります。
StreamingAssetsのアセットとしてダウンロードしたりする場合、GETメソッドを許可すれば良いです。
アセットをダウンロード(変更先サーバーのリソースにGETメソッドでアクセス)する時にレスポンスに次のようなヘッダが追加されていれば良いです。
設定方法はサーバーによって異なるため、各自サーバー環境の仕様やドキュメント等を参考に適切に設定してください。
参考:How to Configure CORS on DigitalOcean Spaces|DigitalOcean Documentation
さいごに
公式では、ビルド出力されるindex.htmlファイルをカスタマイズすることでStreamingAssetsパスを変更する方法が提供されています。
やむを得ず別手段で変更したい場合、ハック的な方法になりますが.loader.jsファイルのStreamingAssetsパスに相当する処理を置換するか、jslibプラグインを実装して動的に書き換えることで実現可能です。
いずれの方法も、最終的にunityInstanceのModule.streamingAssetsUrlのURLを変更するという挙動になる点では共通しています。