Re: note

技術的な知見やポエムなど役に立たない情報を書き連ねる場所

UE4でBluePrint HTTP REST通信

f:id:hik0leaf:20200724173231j:plain

Unreal EngineのBluePrintを使ってHTTP通信を行ってみます。

使用環境:UE4.25.1

1. 準備

BluePrintでHTTP通信を行うために、VaRestというプラグインを使用します。 マーケットプレイスからダウンロードすることができます。無料。

www.unrealengine.com

ダウンロードが終わったらゲームエンジンにインストールします。 次に使用するプロジェクトを開いてメニューの [Edit] > [Plugins]をクリックします。

f:id:hik0leaf:20200724174112j:plain

インストールしたVarestプラグインをEnabledにします。これでBluePrintからVaRestが使えるようになります。

2. GET

レベルブループリントを開いて以下のようにノードを配置します。接続先には httpbin.org を使っています(便利!)。 Xキーを押すと画面上にString型に変換されたJSONが表示されます。

f:id:hik0leaf:20200724174352j:plain

Get String Fieldノードを使用するとJSONオブジェクトから指定したフィールド値を取得することができます。

f:id:hik0leaf:20200724175351j:plain

3. POST

Request BodyにJSONを組み込んでPOSTする方法です。エラーハンドリングを入れています。

f:id:hik0leaf:20200724175603j:plain

成功すると以下のように返ってきます。

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "id": "test_id", 
    "password": "mypassword"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "deflate, gzip", 
    "Content-Length": "30", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "HttpRequest01/++UE4+Release-4.25-CL-13594126 Windows/10.0.18363.1.256.64bit", 
  }, 
  "json": null, 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "http://httpbin.org/post"
}

4. まとめ

VaRestを使うことでBluePrintからHTTP REST通信を行うことができました。VaRestの公式ドキュメントには具体的な方法が記されていなかったので参考になれば幸いです。

本記事の内容もマーケットプレイスQuestions の販売者の回答を参考にしています。より詳しい使い方が知りたい場合は、Questionsの内容を探してみるか販売者に直接質問してみるのが良いかもしれません。

本来であればUE4の標準機能としてBluePrintからHTTP REST通信ができると最高なのですが、あまり需要がないってことなのでしょうかね?

【Android】LiveDataを使った双方向Data Binding

f:id:hik0leaf:20200505225329j:plain

LiveDataを使ってデータをViewに即座に反映させる方法はお馴染みですが、ViewからViewModelへリアクティブに制御する事例はまだ少ないため、ここではMediatorLiveDataを使ってその機能を実装してみたいと思います。

コードは以下の記事を参考にさせていただきました。ありがとうございます。

qiita.com

コード

まずはレイアウトです。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">

    <data>
        <variable
            name="viewModel"
            type="com.example.twowaydatabinding01.MainActivityViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >

        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="ユーザ名"
            android:layout_margin="8dp">

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:text="@={viewModel.username}"/>

        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="パスワード"
            android:layout_margin="8dp">

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:text="@={viewModel.password}"/>

        </com.google.android.material.textfield.TextInputLayout>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:enabled="@{viewModel.canSubmit}"
            android:onClick="@{() -> viewModel.onClick()}"
            android:text="LOGIN"
            />

    </LinearLayout>

</layout>

次に要となるViewModelです。

MainActivityViewModel.kt

package com.example.twowaydatabinding01

import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import timber.log.Timber


class MainActivityViewModel : ViewModel() {

    val username = MutableLiveData<String>()
    val password = MutableLiveData<String>()

    private fun isValid(): Boolean {
        return !username.value.isNullOrBlank() && !password.value.isNullOrBlank()
    }

    val canSubmit = MediatorLiveData<Boolean>().also { result ->
        result.addSource(username) { result.value = isValid() }
        result.addSource(password) { result.value = isValid() }
    }

    fun onClick() {
        Timber.d(username.value + " - " + password.value)
    }
}

最後にActivityです。

MainActivity.kt

package com.example.twowaydatabinding01

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.twowaydatabinding01.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
        binding.viewModel = viewModel
        binding.lifecycleOwner = this
    }
}

実行

よくあるログイン画面の構成です。ユーザ名とパスワードに何かしら入力されるまではLOGINボタンは押せません。ViewModelでユーザ名とパスワードの入力を監視し、両方入力された瞬間にボタンを有効化しています。再びどちらか一方でも空になるとボタンは無効化されます。

f:id:hik0leaf:20200505231447j:plain

まとめ

LiveDataを使って双方向のDataBindingを行うことができました。UIをリアクティブにすることで、ユーザ操作を円滑にするための手助けをすることができます。積極的に取り入れていきたいですね。

参考

Vector Drawableのgradientの挙動にハマった件

グラデーションを表現したSVGファイルをVector DrawableとしてインポートしてViewのBackgroundに配置したときに、Androidのバージョンで差が出たのでそのときの対応メモです。

やりたい表現

Android 8.0 (API 26)以上であればOK

f:id:hik0leaf:20200418223245p:plain

drawable

これをImageViewのbackgroundへ配置

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="200dp"
    android:height="200dp"
    android:viewportWidth="100"
    android:viewportHeight="100">

    <path
        android:pathData="M0,0 L200,0 L200,200 L0,200 Z"
        >
        <aapt:attr name="android:fillColor">
            <gradient
                android:gradientRadius="50"
                android:centerX="50"
                android:centerY="50"
                android:type="radial">
                <item android:offset="0" android:color="#FF0066BA"/>
                <item android:offset="0.47648278" android:color="#FF024D8B"/>
                <item android:offset="1" android:color="#00000000"/>
            </gradient>
        </aapt:attr>
    </path>

</vector>

うまくいかなかった例

Android 5.1.1 - Android 7.1.x (API 22 - 25)

f:id:hik0leaf:20200418223651p:plain

何かおかしい...透過が効いていない?

どのバージョンでもうまくいった例

3つ目の android:offset を2つ目のカラーコードと同じにしてアルファの値のみ0に変更

drawable

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="200dp"
    android:height="200dp"
    android:viewportWidth="100"
    android:viewportHeight="100">

    <path
        android:pathData="M0,0 L200,0 L200,200 L0,200 Z"
        >
        <aapt:attr name="android:fillColor">
            <gradient
                android:gradientRadius="50"
                android:centerX="50"
                android:centerY="50"
                android:type="radial">
                <item android:offset="0" android:color="#FF0066BA"/>
                <item android:offset="0.47648278" android:color="#FF024D8B"/>
                <item android:offset="1" android:color="#00024D8B"/>
            </gradient>
        </aapt:attr>
    </path>

</vector>

結果

f:id:hik0leaf:20200418224342p:plain

まとめ

Vector Drawableの一部の属性がAPI 25以下だと対応していなかったり、アルファ値の扱いが異なるのかもしれません。

Drawable Resource でもだいぶ色々な表現が可能になっていますが、仕様的に表現しきれない部分もあります。一方、Vector Drawableであればデザイナーがイラレ等で用意してくれたSVGファイルをインポートするだけで豊かな表現が可能です。しかし、こちらもインポートが完全ではなく表現が抜け落ちるところは同様にあります。

Vector Drableのインポートで抜け落ちたところは手動設定でカバーすることも可能ですが、設定は大変難しく、将来的にインポート精度が向上するか、もっと簡単に表現できるようになると嬉しいですね。

AndroidのCardViewを使って画像を丸くする

f:id:hik0leaf:20200418194817p:plain

アバター画像を丸く表示する場合、Picassoなどのtransformが良く使われますがコードを書く必要があり少し手間がかかります。代わりにCardViewを使うとXML上でプロパティを指定することで簡単に画像を丸くすることができます。

準備

まずCardViewが使えるようにするために build.gradle に以下の行を追加します。
※今回はAndroidXを使っています。

dependencies {
    implementation 'androidx.cardview:cardview:1.0.0'
}

AndroidXを使わない場合は、以下のリンクを参照してください。

developer.android.com

レイアウト

以下のレイアウトを参考にしてCardViewを追加します。画像を丸くするには cardCornerRadius プロパティを使います。値はCardViewサイズの半分を指定するとちょうど円にすることができます(正方形の場合)。

子要素には画像を表示するためのImageViewを入れてください。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.cardview.widget.CardView
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:cardCornerRadius="100dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" >

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/test_image" />

    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

サンプルで使用した画像はこちらです。私が撮った写真です。 f:id:hik0leaf:20200418200325j:plain

Android Designer上(Android Studio 3.6.2)では残念ながらプレビューはされませんが気にせず進めてください。Android Studioがバージョンアップされればいずれプレビューできるかもしれません。

f:id:hik0leaf:20200418200843p:plain

結果

ビルドして実行すると以下のようになります。

f:id:hik0leaf:20200418201145p:plain


cardCornerRadius の値をCardViewの半分のサイズよりも小さい値を指定すると角丸に指定することができます。下の例では16dpを指定しました。

f:id:hik0leaf:20200418202444p:plain

まとめ

CardViewを使うと cardCornerRadius を指定するだけで簡単に画像を丸くすることができました。今回はImageViewを丸くしましたが、他のViewも子要素に入れることで丸くすることができます。

Android Studioのツールバーにショートカットボタンを置く

f:id:hik0leaf:20190929134521p:plain

Android Studioではよく使う機能をツールバーにショートカットボタンとして配置することができます。 今回はAndroid開発で何かと便利なPluginであるADB Ideaの機能をショートカットボタンに割り当ててみます。

■使用環境

1. ADB Ideaとは

ADB IdeaはAndroid StudioからアプリのアンインストールやKill、RestartなどができるようになるAndroid StudioのPluginです。機能的にはADBコマンドと同じですが、Android Studio上から実行できるため開発効率を上げることができます。

2. ADB Ideaのインストール

Android Studioのメニューから[File] -> [Settings]を選択します。設定画面が開いたら、[Plugins]のメニューをクリックします。

検索欄に「adb idea」と入力して検索するとADB Ideaが出てくるのでクリックします。

f:id:hik0leaf:20190929140141p:plain
ADB Ideaの検索

f:id:hik0leaf:20190929140352p:plain
ADB Ideaのインストール

Installボタンを押します。(画面は既にインストール済みのためInstalledになっています)

インストールが完了すると、Android Studioメニューの[Tools] -> [ADB Idea]からADBコマンドを実行することができます。

f:id:hik0leaf:20190929141001p:plain
ADB Ideaのメニュー

3. ツールバーへのショートカットボタン配置

次にもう一度、Android Studioのメニューから[File] -> [Settings]を選択します。設定画面が開いたら、[Appearance & Behavioer] -> [Menus and Toolbars]をクリックします。

f:id:hik0leaf:20190929144215p:plain
ショートカットボタンの機能割り当て

次に[Main Toolbar] -> [Toolbar Run Action] -> [Run/Debug]を選択した状態で、[+]ボタンから[Add Action]をクリックします。 Actionを選択するウィンドウが表示されるので、[Plugins] -> [ADB Idea] -> [ADB Uninstall App]を選択します。

f:id:hik0leaf:20190929143409p:plain
ショートカットボタンの機能割り当て

また、ボタンにはアイコンを設定することができます。以下のアイコン画像をダウンロードして、C:\Program Files\Android\Android Studio に保存してください。

f:id:hik0leaf:20190929143513p:plain
uninstall.png

アイコンは以下のサイトのフリー素材をAndroid Studioに馴染むようにアレンジしました。ありがとうございます!

icooon-mono.com

アイコンの保存先については任意の場所で構いませんが、ファイル名を変更したり、保存先を変更するとAndroid Studioから見えなくなるので、普段あまり触らないAndroid Studioと同じ場所に保存しておくのが良いでしょう。

保存したら[Set icon]ボタンで保存先のアイコンを設定します。 (アイコンは後からでも設定できます)

[OK]ボタンを押すと[Menus and Toolbars]上で「ADB Uninstall App」ボタンが追加されていることが確認できます。さらに△と▽ボタンを押すと順番(位置)を変更することができます。

f:id:hik0leaf:20190929150318p:plain
ツールバー上のショートカットボタン

[Apply]または[OK]ボタンを押すとツールバー上にアンインストールボタンが追加されます。

4. まとめ

Android Studioツールバーをカスタマイズする方法を解説しました。Androidパーミッション関連はとても複雑なため、初回起動の処理をデバッグするために頻繁にアプリのインストールとアンインストールを繰り返す必要があります。そのため、このアプリのアンインストールボタンがあると効率良くデバッグすることができます。

今回はADB Ideaの機能を割り当てましたが、他にもデフォルト以外の様々な機能を割り当てることができるので、是非、自分好みにカスタマイズしてみてください。

UnityWebRequestを使ってBasic認証する

f:id:hik0leaf:20190907233633p:plain

UnityWebRequestを使ってBasic認証する方法です。 サンプルコードのBasic認証のテストとして以下のサイトを使わせていただきました。

leggiero.sakura.ne.jp

1. コード

以下のスクリプトを適当なGameObjectにアタッチします。

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class MainScript : MonoBehaviour
{
    private string url = "http://leggiero.sakura.ne.jp/xxxxbasic_auth_testxxxx/secret/kaiin_page_top.htm";

    void Start()
    {
        StartCoroutine(WebRequest("kaiin", "naisho"));
    }

    IEnumerator WebRequest(string id, string pass) {

        UnityWebRequest request = UnityWebRequest.Get(url);

        // Basic認証用のAUTHORIZATIONヘッダー付加
        string authorization = authenticate(id, pass);
        request.SetRequestHeader("AUTHORIZATION", authorization);

        yield return request.SendWebRequest();

        if (request.isNetworkError) {
            Debug.Log(request.error);
        } else {
            Debug.Log(request.responseCode);
        }
    }

    string authenticate(string username, string password) {
        string auth = username + ":" + password;
        auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
        auth = "Basic " + auth;
        return auth;
    }
}

2. 実行結果

認証に失敗すると 401 (Unauthorized)

f:id:hik0leaf:20190907234453p:plain
失敗 (401 Unauthorized)

成功すると 200 (OK)が返ります。

f:id:hik0leaf:20190907234532p:plain
成功 (200 OK)

返り値のbodyは request.downloadHandler.text で取得することができます。

UniWebView 3を使う

f:id:hik0leaf:20190906233703p:plain

Unity上でWebブラウザの機能を使えるようにするためのWebViewアセットはいくつかありますが、ここではその一つであるUniWebView 3の解説を行います。

1. UniWebView 3とは

Unity上でWebブラウザを表示することができるアセットで、インターネットWebブラウジングだけでなく、ローカルHTMLの読み込みやCSSスタイリング、Javascriptの実行が可能です。

$25の有料アセット(2019.09時点)なだけあって ドキュメント がしっかり整備されています。使用する際はドキュメントを参照すると良いでしょう。

対応プラットフォームはiOS 9.0以上、Android 5.0以上に対応しており、macOSのUnity Editor上でも動作します。ただmacOSのUnity Editorで動かすときは、Scene ViewやGame View内ではなく独立のウィンドウで表示されるためデバッグ用途としてはやや使いづらい部分があります。

また、Windowsには対応していないことからもモバイルプラットフォーム向けのアセットといえます。

2. 導入

Asset StoreからUniWebView 3を購入してインポートします。

assetstore.unity.com

3. ひとまず使ってみる

インポートできたらProjectの UniWebView > Demo > UniWebViewDemo シーンを開きます。実行すると以下のようにウィンドウが開いてUniWebViewのドキュメントサイトが表示されます。

f:id:hik0leaf:20190907111905p:plain
デモシーンの場所

f:id:hik0leaf:20190907111947p:plain
デモシーンの実行結果

接続先を変更したい場合はヒエラルキーにあるUniWebView PrefabにアタッチされているUniWebView Scriptの Url On Start の欄に任意のURLを入力します。

f:id:hik0leaf:20190907112212p:plain
接続先の変更

4. 色々使ってみる

ドキュメントには チュートリアル がありますので、これに沿って進めていくと大体いい感じに使えるようになります。ここでは要点だけに絞って解説します。

まずは任意のシーンに空のGameObjectを作成して WebView と名前を付けます。次にProjectに WebView というスクリプトを作成して、先ほど作成したWebViewオブジェクトにアタッチします。

f:id:hik0leaf:20190907114729p:plain
WebViewオブジェクトの作成とスクリプトのアタッチ

スクリプトに以下のコードを貼り付けます。

using UnityEngine;

public class WebView : MonoBehaviour
{
    UniWebView webView;

    void Start () {
        var webViewGameObject = new GameObject("UniWebView");
        webView = webViewGameObject.AddComponent<UniWebView>();

        webView.Frame = new Rect(0, 0, Screen.width, Screen.height);
    
        webView.Load("https://www.google.co.jp/");
        webView.Show();
    }
}

実行すると以下のようになります。

f:id:hik0leaf:20190907131827p:plain
実行結果

5. ローカルHTMLファイルの読み込み

次にネット上のサイトではなく、ローカルにあるHTMLファイルを読み込んで表示させてみます。

まず StreamingAssets フォルダを作成します。

f:id:hik0leaf:20190907132308p:plain
StreamingAssetsフォルダの作成

以下のHTMLファイルを作成し、sample.html と名前を付けてStreamingAssets フォルダに保存します。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        Hello World
    </body>
</html>

先ほど作成したスクリプト WebView.cs を以下のように変更します。

void Start () {
    var webViewGameObject = new GameObject("UniWebView");
    webView = webViewGameObject.AddComponent<UniWebView>();

    webView.Frame = new Rect(0, 0, Screen.width, Screen.height);

    var url = UniWebViewHelper.StreamingAssetURLForPath("sample.html");
    webView.Load(url);
    webView.Show();
}

実行すると以下のように表示されます。StreamingAssets フォルダ内にjavascriptファイルやcssファイルを配置すればHTMLから参照することが可能です。

f:id:hik0leaf:20190907134028p:plain
ローカルHTMLファイルの表示結果

6. Unity(C#) → WebView(Javascript)の通信

UniWebViewではUnity側からJavascriptの関数を実行することが可能です。

sample.html を以下のように変更します。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        Hello World
    </body>

    <script language="javascript" type="text/javascript">
        function SumTest(a, b) {
            return a + b;
        }
    </script>
</html>

WebView.cs を以下のように変更します。

using UnityEngine;

public class WebView : MonoBehaviour
{
    UniWebView webView;

    void Start () {
        var webViewGameObject = new GameObject("UniWebView");
        webView = webViewGameObject.AddComponent<UniWebView>();

        webView.Frame = new Rect(0, 0, Screen.width, Screen.height);
    
        var url = UniWebViewHelper.StreamingAssetURLForPath("sample.html");
        webView.Load(url);
        webView.Show();
    }

    void Update() {
        if (Input.GetKeyDown(KeyCode.Space)) {
            webView.EvaluateJavaScript("SumTest(1, 2)", (payload) => {
                if (payload.resultCode.Equals("0")) {
                    Debug.Log("1 + 2 = " + payload.data);
                }
            });
        }
    }
}

実行してスペースキーを押すと以下のようになります。

f:id:hik0leaf:20190907140352p:plain
実行結果

Unity→Javascript関数の実行は以下の部分で行っています。EvaluateJavaScript の第一引数でHTMLファイル側に記述したJavascriptの関数名を指定します。今回の例では引数も一緒に渡しています。

さらにJavascript関数の戻り値も第二引数で受け取ることが可能になっています。例ではラムダ式を用いてpayload変数で値を受け取っています。戻り値には resultCode が付与されており、0 で正常終了。0 以外はエラーと判断することができるようになっています。

webView.EvaluateJavaScript("SumTest(1, 2)", (payload) => {
    if (payload.resultCode.Equals("0")) {
        Debug.Log("1 + 2 = " + payload.data);
    }
});

うまくいかない場合は resultCode を調べてみると良いでしょう。Javascriptの関数名が間違っていたりするとエラーになります。戻り値のデータは data で取得することができます。

7. WebView(Javascript) → Unity(C#)の通信

Javascript側からUnity側の関数を呼び出すことも可能です。

sample.html を以下のように変更します。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <input type="text" id="mytext">
        <input type="button" id="btn" value="OK" onclick="OnButtonClick();">
    </body>

    <script language="javascript" type="text/javascript">
        function OnButtonClick() {
            var message = document.getElementById('mytext').value;
            window.location.href = "uniwebview://action?value1=" + message + "&value2=" + "hoge";
        }

        function SumTest(a, b) {
            return a + b;
        }
    </script>
</html>

WebView.cs を以下のように変更します。

using UnityEngine;

public class WebView : MonoBehaviour
{
    UniWebView webView;

    void Start () {
        var webViewGameObject = new GameObject("UniWebView");
        webView = webViewGameObject.AddComponent<UniWebView>();

        webView.Frame = new Rect(0, 0, Screen.width, Screen.height);
    
        var url = UniWebViewHelper.StreamingAssetURLForPath("sample.html");
        webView.Load(url);
        webView.Show();

        webView.OnMessageReceived += (view, message) => {
            if (message.Path.Equals("action")) {
                Debug.Log("value1: " + message.Args["value1"]);
                Debug.Log("value2: " + message.Args["value2"]);
            }
        };
    }

    void Update() {
        if (Input.GetKeyDown(KeyCode.Space)) {
            webView.EvaluateJavaScript("SumTest(1, 2)", (payload) => {
                if (payload.resultCode.Equals("0")) {
                    Debug.Log("1 + 2 = " + payload.data);
                }
            });
        }
    }
}

実行するとWebView上でText入力とボタンが表示されるので、Textに適当な値を入れて[OK]ボタンを押します。

f:id:hik0leaf:20190907143607p:plain
Javascript→Unityへの送信

うまく動作すると以下ようにDebug.Logに表示されます。

f:id:hik0leaf:20190907143932p:plain
実行結果

JavascriptからUnityへは

window.location.href = "uniwebview://action?value1=" + message + "&value2=" + "hoge";

で値を送ることができます。& でパラメータをつなげることで複数の値を送ることができます。

Unity側は

webView.OnMessageReceived += (view, message) => {
    if (message.Path.Equals("action")) {
        Debug.Log("value1: " + message.Args["value1"]);
        Debug.Log("value2: " + message.Args["value2"]);
    }
};

で値を受け取っています。メッセージのPathはactionとしていますが送り手と受け手で一致していれば任意の値で構いません。値は message.Args[""] でキーを指定することで取得することができます。

8. まとめ

UniWebView 3を使うとUnity上でWebブラウザの機能が使えることがわかりました。Unity上からJavascriptを使ってWebの豊富な資源を活用したり、洗練されたUIなどを流用することができるようになるため、手段の1つとして覚えておくと便利でしょう。