Kitsune Gadget

気になったことをつらつらと

Unity WebGLビルドの問題について(ホスティングとサウンド)

この記事では バージョン 2020.2.0f1 において書いています。

Unityで制作したアプリをWebGLアプリとしてビルドして、実際にテストしたときにかなりハマりそうな部分に出会いました。ここでは大きくWebGLビルドで発生した2つの問題の紹介と対策を書くことにします。

リモートホスティングの問題

WebGLの "Build And Run" においてローカルサーバーを起動すると正しく読み込むことができます。しかし、リモートのホスティングサービス等を経由してアプリを読み込もうとすると unityFramework not defined at HTMLScriptElement.script.onload となってしまいます。
これは既に報告されている問題のようで、サーバー設定を行うことで回避できるようです。

原因はビルド時の圧縮にあります。Project Settings > Player > Publishing Settings にある圧縮方式で BrotliGzip もしくは無圧縮の Disabled を選ぶことができます。今まではビルド内にユニバーサルなローダーを出力しており、様々なUnityバージョンに対応できるようにしていたそうです。(その中に圧縮ファイルの展開も含まれていました。)

f:id:kitsune-gadget:20210118165019p:plain
Compression Format の項目で圧縮方式を選ぶ

さて、バージョン 2020.1 からは、パフォーマンスを向上させるためにローダーには必要なスクリプトのみ出力するようにしたようです。つまるところ圧縮ファイルの展開スクリプトは用意されておらず、サーバー側でリクエスト応答時に自動展開するようにしなければなりません。

細かいことを言うと、サーバー側で Content-TypeContent-Encoding を応答ヘッダーに追加する必要があります。
簡単に言えば、圧縮展開をブラウザの機能でしてもらうということです。

サーバー構成にアクセスできる場合はUnityのドキュメントにあるように圧縮に対応するように設定を置くことで解決できます。

docs.unity3d.com

しかしながらほとんどのホスティングサービスの通常設定では対応していないようで、展開されずにファイルが存在しないようになってしまいます。 それによって上記のエラーが発生します。

例えば、Netlifyではルートに netlify.toml を作成し、設定を記述することである程度のサーバー構成の対応ができます。

docs.netlify.com

ちなみに、知る限りNetlifyはレポジトリサービスから直接ページビルドができる利点がありますが、ダウンロード帯域に制限が掛かっているらしく、直接の画像等の読み込みは極端に遅いです。

Decompression Fallback

では、サーバー設定できない場所はどうするのかというと、しっかり対応がされています。ネイティブに展開できない場合、先程の公開設定から下にある Decompression Fallback にチェックを入れておくと、圧縮展開用のスクリプトも含まれるようになります。その代わりローダーのサイズが大きくなるとのこと。

f:id:kitsune-gadget:20210118170347p:plain
Decompression Fallback を有効にする

このときのファイルの拡張子は Development Build でなければ .unityweb になっていました。

圧縮なしと有りでは2~4倍ほどのファイルサイズ差があるため、圧縮なしでWebGLアプリを公開する場合はアプリケーション本体のロード時間を犠牲にする必要がでてきます。Decompression Fallback でローダーのサイズが増えるのと、圧縮しないアプリケーションそのもののサイズ増減とでどちらが大きいかで決めるのも良いかもしれません。
(基本的に圧縮したほうがサイズは小さくなりそうですが)

音が出ない問題

2つ目の問題は、音が鳴らないこと。この問題に直面する人は結構多いようです。
2年前くらいは、Chrome等のブラウザの音声再生のポリシーが変わったからであると言われていました。
これはページを開いた途端に音が自動再生されないようになり、一度ユーザーが何かしらのアクションを起こしてからではないと音声が鳴らないというものです。

developers.google.com

これについては、既に修正されているはずで Build.framework.js を見ても、_JS_Sound_Init() では AudioContext.resume() を自動的にするようになっています。
(それでもAudioContextを作成した段階で、warning が表示されるのは気になります…)

しかしながら、通常の再生で音は鳴ることはありませんでした。

遅延させると音が出る

自分がちょうど遅延再生をする機能を取り入れてなかったら闇に落ちていた可能性がありました。 遅延を入れていたところだけ音が鳴っていたのです。
なぜかはわかりませんが、 AudioSource.PlayDelayed(float delay) を利用して 0.0000001f でも遅延させればなんと音がしっかり出ました。

完全な0だと音が出ません。0.00000001でも遅延させると音が出ます。

Build.framework.js における Web Audio API 設定周りの問題かと多少調査しましたが、特に問題はありませんでした。どちらかというとビルドデータ本体の再生周りに問題がありそうだと思っています。 WebGLビルドで音が出ない問題に直面している人は、最小遅延再生を試してみて欲しいです。

まとめ

2020.1 からWebGLのビルド周りが大きく変わっていたようです。しかし、あまりまだ日本語の記事が多くないように見受けられます。過去のUnityをそこまで知らないですが、以前のWebGLビルドからはかなり最適化が進んでいるようですね。

話が変わりますが、Webの全画面表示の機能(Fullscreen API)もUnity側でネイティブアプリと同じように呼び出すことができます。ところが、このAPIに対応しているはずの AndroidChrome で例外を吐いてしまいました。これについてはまた調査したいと思います。

参考

最後に

Unityを利用して制作した Guitar Chord Creator を公開しています。

kitsunegadget.github.io

ギタープレイヤーの皆さんや、ギターでこういう押さえ方したら響きが良かったけど何のコードかよくわからない等のような人向けに、ポジションをクリックしていくだけで簡単にコードが分かるようなアプリです。

デザインやコードの表記にまだ最適解が見つかっていませんが、基本的なコードはしっかり表示できるようにしてあります。

バグ発見、こうしたほうが良いとか、こういう機能が欲しい等有りましたら。 @kitsunegadget へ報告していただくとありがたいです。