🤳 UnityのWebGLでスマホ判定

2022-11-30 /Development #Unity

WebGLでPCとスマホの両方から使うコンテンツを作っていて、スマホの判定をする必要があったので実装してみたものの、つまづきどころがいくつかあったので次回困らないようにメモ。


実装方法は以下。

Unityでユーザーエージェントを受け取るためのプラグインを作成する

まずは /Assets/Plugins/GetUserAgent.jslib というファイルを作って、Unityにメッセージを送信するプラグインを作成します。

コピーしました
mergeInto(LibraryManager.library, {
    GetUserAgent: function () {
        window.unityInstance.SendMessage('UAChecker', 'SetUserAgent', window.navigator.userAgent.toLowerCase())
    },
});

テンプレートHTMLを作成+設定する

上記.jslibを使ってUnityにメッセージを送信するのですが、グローバル変数にunityInstanceが無いとSendMessageがUnityまで届かないので、createUnityInstance後の返り値であるunityInstanceをグローバル変数に設定するようにテンプレートを修正します。

/Assets/WebGLTemplates/TestUAChecker/ に一旦ビルドしたファイル群をコピーして、index.htmlを編集します。

コピーしました
script.onload = () => {
  createUnityInstance(canvas, config, (progress) => {
    progressBarFull.style.width = 100 * progress + "%";
  }).then((unityInstance) => {
    loadingBar.style.display = "none";

    window.unityInstance = unityInstance;//<--追加分

    fullscreenButton.onclick = () => {
      unityInstance.SetFullscreen(1);
    };
  }).catch((message) => {
    alert(message);
  });
};

あとは、 Edit > Project Settings > Player > Resolution and Presentation でWebGLビルドの際に上記で作成したテンプレートを使用するように設定しておきます。

C#スクリプトからプラグインを呼び出す

あとはプロジェクト内で実際に動かすスクリプト、UAChecker.csを作成します。

コピーしました
using System.Runtime.InteropServices;
using UnityEngine;

public class UAChecker : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void GetUserAgent();

    public static string ua { get; private set; } = "";

    void Start()
    {
#if (UNITY_WEBGL && !UNITY_EDITOR)
        GetUserAgent();
#endif
    }

    public void SetUserAgent(string value)
    {
#if (UNITY_WEBGL && !UNITY_EDITOR)
        ua = value;
#endif
    }

    public static bool IsSmartPhone
    {
        get
        {
            return ua.Contains("iphone") || ua.Contains("android");
        }
    }
}

ゲーム開始時にGetUserAgentを実行したら、JavaScript側からSetUserAgentが返ってくるので、送られてきたユーザーエージェントを保存しているだけです。

.jslibではUACheckerという名前をつけたGameObjectにSendMessageするように記載したので、UACheckerという名前をつけたGameObjectを作成してこのスクリプトをアタッチしておきます

スマートフォンのチェックはUAChecker.IsSmartPhoneを実行すると、保存されているユーザーエージェントから判定して真偽値を受け取れるようになっています(他の判定がしたい時にもプラグインを修正する手間を省きたいのでこんな作りにしています)。

コピーしました
if(UAChecker.IsSmartPhone)
{
  //スマホの場合の挙動
};

UACheckerにユーザーエージェントが保存された後にしか正しい値が帰ってこないので、Start以降に参照する必要があります。

スクリプトの実行順を設定する

それで、最初の話に戻るのですが何につまづいたかというと、

  • ユーザーエージェントのチェックをしたいスクリプト達がUACheckerを参照する時に、まだ初期化されていない事がある
  • 上記理由からUACheckerが最初に動いてほしいのでAwakeOnEnableに入れてみたものの、まだunityInstanceが準備されていないみたいで動作せず
  • 仕方なしにStartGetUserAgentを記載
  • それだとやはり使う側のStartが先に実行されてしまう事がある

という流れで正しい値が取れてなくてオヤっとなったのですが、スクリプトの実行順を設定する事で解決しました。 なんか最初動いてた気がしてたのに、いつの間にか動かなくなっていて不思議だったんですがどこかで実行順が前後したのが原因だったのかも…

スクリプトの実行順は[DefaultExecutionOrder(-1)]とか書いておいても良いのですが、どこかで非推奨になるみたいな記事を見かけたような見かけてないような気がしたので、Script Execution Orderから設定しました。

Edit > Project Settings > Script Execution Order にこんな感じで追加しておくと想定していた通りに動作してくれます。


参考リンク:

Comment
comments powered by Disqus
Profile

石原 悠 / Yu Ishihara

デザインとプログラミングと編み物とヨーグルトが好きです。