のりまき日記

Unityなどの活用リファレンスブログ。「こうしたい時どうする」をまとめたい

unity)ディープリンク(URLスキーム)をeditorにも対応させたい

完成図

はじめに

unityはディープリンクにも対応していますが、エディターには対応していませんでした。デバッグする際にエディターでも確認できると便利なので実装してみます。

docs.unity3d.com

やること

ディープリンクはURLを使ってアプリを開く仕組みです。通常「myapp://scheme」みたいに指定するところを、「http://localhost/scheme」と指定してもURLなので動くはずです。今回はエディターにwebサーバーを立てることで独自にディープリンクを処理させてみます。

webサーバーに関しては以下の記事の実装を使います。

tsururin.hatenablog.com

ディープリンクのハンドリング

通常のハンドリングに加えて、webサーバーでもハンドリングできるようにします。

using System.Web;
using UnityEngine;

public class DeepLinkHandler : MonoBehaviour
{
    public const int EditorSchemePort = 3333;

    public event System.Action<string> onDeepLinkRequest;

#if UNITY_EDITOR
    Server m_Server;
#endif

    private void OnEnable()
    {
        // 通常の処理
        Application.deepLinkActivated += OnDeepLinkActivated;

#if UNITY_EDITOR
        // エディター用の処理
        m_Server = new Server(EditorSchemePort);
        m_Server.Route(new SchemeHandler(OnDeepLinkRequest));
        m_Server.Start();
#endif
    }

    private void OnDisable()
    {
        // 通常の処理
        Application.deepLinkActivated -= OnDeepLinkActivated;

#if UNITY_EDITOR
        // エディター用の処理
        m_Server.Stop();
#endif
    }

    void OnDeepLinkActivated(string url)
    {
        var uri = new System.Uri(url);
        var query = HttpUtility.ParseQueryString(uri.Query);
        var data = query.Get("data");
        OnDeepLinkRequest(data);
    }

    void OnDeepLinkRequest(string data)
    {
        onDeepLinkRequest?.Invoke(data);
    }
}
using System.Net;
using System.Text;
using System.Threading.Tasks;

public class SchemeHandler : IRequestHandler
{
    public string path => "/scheme";

    public string method => "GET";

    System.Action<string> m_Callback;

    public SchemeHandler(System.Action<string> callback)
    {
        m_Callback = callback;
    }

    public Task<bool> Handle(HttpListenerRequest req, HttpListenerResponse res)
    {
        var data = req.QueryString.Get("data");

        res.StatusCode = 200;
        var text = Encoding.UTF8.GetBytes("success! open unity editor.");
        res.OutputStream.Write(text, 0, text.Length);
        res.Close();

        m_Callback?.Invoke(data);

        return Task.FromResult(true);
    }
}

動かしてみる

unityからブラウザを起動して、ブラウザからunityに処理を戻してみます。ついでにdataも渡してみます。

server側

まずはwebページが必要なので、以下のようなindex.htmlを作ります。

<html>
    <head>
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   </head>
    <body>
        <h1>My Deep Link Test page</h1>
        <p><a id="link" href="">unityに戻る</a></p>

        <script>
           const searchParams = new URLSearchParams(window.location.search);
           let scheme = searchParams.get("scheme");
            scheme += "?data=ok";
           document.getElementById("link").setAttribute("href", scheme);
       </script>
    </body>
</html>

pythonで簡易サーバーを起動します。これでhttp://localhost:8080/で上記HTMLのページが表示されます。

% cd test
% python3 -m http.server --cgi 8080

note

const searchParams = new URLSearchParams(window.location.search);
let scheme = searchParams.get("scheme");
scheme += "?data=ok";

ブラウザがアプリ起動に使うURLは、unityから渡してあげるようにします。ブラウザ側ではエディターから呼ばれたのか、アプリから呼ばれたのかわからないためです。

unity側

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

public class Test : MonoBehaviour
{
    [SerializeField]
    Text m_Message;

    [SerializeField]
    DeepLinkHandler m_DeepLinkHandler;

    void Start()
    {
        m_Message.text = "アイルビーバッグ";
    }

    private void OnEnable()
    {
        m_DeepLinkHandler.onDeepLinkRequest += OnDeepLinkRequest;
    }

    private void OnDisable()
    {
        m_DeepLinkHandler.onDeepLinkRequest -= OnDeepLinkRequest;
    }

    public void OnOpenURL()
    {
        var scheme = "myapp://scheme";
#if UNITY_EDITOR
        scheme = "http://localhost:3333/scheme";
#endif
        Application.OpenURL(string.Format("http://localhost:8080?scheme={0}", scheme));
    }

    void OnDeepLinkRequest(string data)
    {
        m_Message.text = string.Format("もどったぞ(data: {0})", data);
    }
}

これで動きました。

完成図

おわり

ブラウザからエディターを操作してる感じがして、なんだか面白いです。ほかにも活かせそうだと思いました。