【Unity(C#)】UniWebView4使ってUnityでWebView表示

##はじめに
[UniWebView4](https://assetstore.unity.com/packages/tools/network/uniwebview-4-175993)とはアプリ内でWEBサイトを表示したい場面で役に立つアセットです。

初めて使用する際にいろいろとわからないことが多かったので
メモを残しておきます。

## バージョン情報

| 諸々名前 | バージョン |
|:-:|:-:|
|  Unity | 2020.3.4f1  |
|  UniWebView4 | 4.9.0  |
|  UniRx | 7.1.0  |

##デモ

フルスクリーンで半透明のWebViewを表示し、WebView上のボタン押下でCubeを動かすサンプルです。

![WebViewDemo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/8de94df7-f428-6bd4-a4f6-98a4b1b30518.gif)


##コード

まずはHTMLです。
デモなので超簡易です。作成したら`StreamingAssets`に保存します。

```html
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=yes" />

<head>
  <title>Sample</title>
</head>

<head>
  <a href="web-view-demo://close">
    <button style="position: fixed;
    top: 10px; 
    right: 10px;
    padding: 6px 40px;">閉じる</button>
  </a>
</body>  

<li>
  <a href="web-view-demo://up">
    <button>↑</button>
  </a>
</li>

<li>
  <a href="web-view-demo://down">
    <button>↓</button>
  </a>
</li>

<li>
  <a href="web-view-demo://right">
    <button>→</button>
  </a>
</li>

<li>
  <a href="web-view-demo://left">
    <button>←</button>
  </a>
</li>

```

フルスクリーン表示する際はHTML側でレスポンシブ対応しておかないとios端末で正しく表示されませんでした。

```html
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=yes" />
```

---

次にC#側のWebView生成コードです。


```C#
using UniRx;
using UniRx.Triggers;
using UnityEngine;

/// <summary>
/// WebViewクラス
/// </summary>
public class WebViewDemo
{
    /// <summary>
    /// UniWebView
    /// </summary>
    private UniWebView _uniWebView;

    /// <summary>
    /// WebViewを生成
    /// </summary>
    /// <param name="player">動かすオブジェクト</param>
    /// <param name="backGroundColor">背景色</param>
    /// <param name="url">開きたいURL</param>
    public void ShowWebViewPlayerController(string url, Transform player, Color? backGroundColor = null)
    {
        //既に存在している場合は開くだけ
        if (_uniWebView != null)
        {
            _uniWebView.Show();
            return;
        }

        var webViewObject = new GameObject("WebViewObject");
        //キャッシュのクリア
        webViewObject.OnDestroyAsObservable().Subscribe(_ => _uniWebView.CleanCache()).AddTo(webViewObject);
        _uniWebView = webViewObject.AddComponent<UniWebView>();

        //スキームを追加
        _uniWebView.AddUrlScheme("web-view-demo");

        //メッセージ受け取りイベント
        _uniWebView.OnMessageReceived += (view, message) =>
        {
            switch (message.Path)
            {
                //閉じるボタン押下
                case "close":
                    //WebViewを非表示にする
                    if (_uniWebView != null) _uniWebView.Hide(true);
                    break;

                //↑ボタン押下
                case "up":
                    player.Translate(Vector3.forward);
                    break;

                //↓ボタン押下
                case "down":
                    player.Translate(Vector3.down);
                    break;

                //→ボタン押下
                case "right":
                    player.Translate(Vector3.right);
                    break;

                //←ボタン押下
                case "left":
                    player.Translate(Vector3.left);
                    break;
            }
        };

        //画面の向きが変わるたびに解像度を変更
        _uniWebView.OnOrientationChanged += (view, orientation) =>
        {
            _uniWebView.Frame = new Rect(0, 0, Screen.width, Screen.height);
        };

        //画面サイズを設定
        _uniWebView.Frame = new Rect(0, 0, Screen.width, Screen.height);

        //背景色
        var color = Color.white;
        color.a = 0.5f;
        _uniWebView.BackgroundColor = backGroundColor ?? color;

        //ツールバー非表示
        _uniWebView.SetShowToolbar(false);
        //横スクロールバー非表示
        _uniWebView.SetHorizontalScrollBarEnabled(false);

        //インジケータ
        _uniWebView.SetShowSpinnerWhileLoading(true);
        _uniWebView.SetSpinnerText("ロード中");

        //内部保持してるサイトを読み込み
        var exchangeUrl = UniWebViewHelper.StreamingAssetURLForPath(url);
        _uniWebView.Load(exchangeUrl);

        //画面表示
        _uniWebView.Show();
    }
}
```

OnMessageReceivedで受け取ったメッセージに応じた処理を行っています。
当然ながら、HTML側のスキーム等、C#側と合わせないと動きません。

###構造体をデフォルト引数に

小ネタですが、Colorをデフォルト引数として設定するのは構造体の都合上難しいようでした。
【参考リンク】：[Unity3d c# - Vector3 as default parameter](https://stackoverflow.com/questions/30294216/unity3d-c-sharp-vector3-as-default-parameter)

ですので、下記のようにNull許容型として定義し、関数内で値の有無を見てデフォルト値を設定しています。

```C#
 public void Hoge(Color? c = null)
 {
    var defaultColor = Color.white;
    hogehoge.Color = c ?? defaultColor ;
 }
```

`??`はNull合体演算子と呼ばれるもので、`??`の左側が評価されて`null`を返した場合、`??`の右側を評価するという書き方です。
【参考リンク】：[??（null合体演算子）](https://qiita.com/Nossa/items/1fd4881a0b97a5f32901#null%E5%90%88%E4%BD%93%E6%BC%94%E7%AE%97%E5%AD%90)

---

最後に使う側のサンプルです。
ボタン押下で指定したHTMLのWebViewを開きます。

```C#
using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    [SerializeField] private Button _testButton;
    [SerializeField] private Transform _player;
    
    void Start()
    {
        _testButton.onClick.AddListener(ShowWebView);
    }

    private void OnDestroy()
    {
        _testButton.onClick.RemoveListener(ShowWebView);
    }

    private void ShowWebView()
    {
        var webView = new WebViewDemo();
        webView.ShowWebViewPlayerController("SampleHTML.html",_player);
    }
}
```

##最後に
超簡単かつドキュメントがしっかりしていて、有料の価値のある非常に良いアセットだと個人的には思いました。

一点だけ下記直せずです。
iosだと問題なく動いたのですが、手元のAndroid端末(ver11)だと
`Hide`の呼び出し時に一瞬カクついてWebViewが閉じるバグがありました。

何か知ってる人いたら助けてください。

##参考リンク
[UniWebView](https://uniwebview.com/)
[もう逃げない。HTMLのviewportをちゃんと理解する](https://qiita.com/ryounagaoka/items/045b2808a5ed43f96607)