Unityで WebView を使うにあたって、表示中のURLの文字列やページの更新状況、ページの進む戻るといった制御をしたくなるケースが出てくるかと思います。
今回はこれら基本的なブラウザ制御手順について説明します。
なお、本記事ではEvaluateJS()を使用しない実装になっています。それはiOSでEvaluateJS()を使用したURL取得を行った場合、正しく動作しなかったためです。
散々ほかのサイトではEvaluateJS()を使うとできるよとあったのですが、どうしても正しいURLが取得できないタイミングがあったため、使わない方法で実現しています。
Webviewはグリーさんから公開いただいているアセット unity-Webview を使わせていただきております。また、Webviewの基本的な使い方や配置の仕方についてはこちらの記事にまとめております。
WebViewの更新状態と表示ページのURL取得
Webの更新状態を取得するためにInit()でstartedとldのコールバックを登録します。
startedは更新が開始されたよというコールバックで、ldは更新が完了したよというコールバックです。
スクリプト
以下に更新状態とURLを取得するスクリプトをまとめます。
void Start()
{
int[] margins = new int[4];
Vector3[] corners = new Vector3[4];
/* Textエリアの4箇所の座標を取得 */
/* 左下、左上、右上、右下 */
BaseTargetPanel.GetComponent<RectTransform>().GetWorldCorners(corners);
/* Textエリアの4箇所の座標をScreen座標に変換 */
Vector2[] spos = new Vector2[4];
spos[0] = Camera.main.WorldToScreenPoint(corners[0]); /* 左下 */
spos[1] = Camera.main.WorldToScreenPoint(corners[1]); /* 左上 */
spos[2] = Camera.main.WorldToScreenPoint(corners[2]); /* 右上 */
spos[3] = Camera.main.WorldToScreenPoint(corners[3]); /* 右下 */
/* 黄色矢印の長さを計算 */
margins[0] = Math.Abs((int)spos[0].x); /* 左オフセット */
margins[1] = margins[0] + Math.Abs(Screen.height - (int)spos[0].y + (int)spos[0].x); /* 上オフセット */
margins[2] = margins[0]; /* 右オフセット */
margins[3] = margins[0]; /* 下オフセット */
webViewObject = (new GameObject("WebViewObject")).AddComponent<WebViewObject>();
webViewObject.Init(
started: (msg) => {
Debug.Log("started");
Debug.Log(msg);
if (webViewObject.Progress() != 100) {
isLoading = true;
}
},
ld: (msg) => {
isLoading = false;
Debug.Log("ld");
Debug.Log(msg);
if (msg.StartsWith("https")) {
url = msg;
}
if (msg.StartsWith("http")) {
url = msg;
}
if (msg.StartsWith("url:")) {
url = msg.Substring(4);
}
},
enableWKWebView: true);
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
webViewObject.bitmapRefreshCycle = 1;
#endif
webViewObject.LoadURL("https://www.google.co.jp");
/* 表示位置を決定 */
webViewObject.SetMargins(margins[0], margins[1], margins[2], margins[3]);
webViewObject.SetVisibility(true);
}
public bool IsLoading()
{
return isLoading;
}
public string GetURL()
{
return url;
}
スクリプト解説
今回はStart()でGoogleの検索ページを表示するようになっています。
ユーザーは何かしら検索文字を入れて検索するのですが、検索を開始したことをUnity上で検知するためにInit()でstarted:を登録しています。
そして、検索が終わり、ページが表示されるとld:がコールバックされ、そのURLをmsgで受け取り、変数に格納しています。
ここでstartedでisLoadingをtrueにしていますが、以下の条件が入っています。
if (webViewObject.Progress() != 100) {
isLoading = true;
}
これはiOSでみられる現象なのですが、あるページを表示するとき、started→ld→started→started→・・・というように表示完了のldがコールバックされているにも関わらず、連続してstartedが呼ばれるという現象が起きています。
startedはメインページ以外に小物や広告のダウロードを開始するたびにも呼ばれているようです。これをやられてしまうと、いつユーザー操作で更新開始したのかわからなくなり、URLの更新を待たせることもできなくなってしまいます。
そこで、webViewObject.Progress()で更新状況を取得して、進捗100%でコールバックされたstaredは無視するようにしています。小物のロードは進捗100%でコールバックされていました。
この対応により不要にisLoadingを立てることがなくなり、ユーザー操作による更新開始からロード完了まで正確に知ることができています。
最後にブラウザの戻る進む機能です。
スクリプト
public void GoBack()
{
if (webViewObject.CanGoBack()) {
webViewObject.GoBack();
}
}
public void GoForward()
{
if (webViewObject.CanGoForward()) {
webViewObject.GoForward();
}
}
GoBack()で戻って、GoForward()で進みます。スクリプトは先ほどのものにマージすればよいです。
状態を表示するためのスクリプト
状態を表示するTextに以下のスクリプトをアタッチしました。
using UnityEngine;
using UnityEngine.UI;
public class StateText : MonoBehaviour
{
public GameObject WebViewSample;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (WebViewSample.GetComponent<WebViewSample>().IsLoading()) {
gameObject.GetComponent<Text>().text = "更新中・・・";
} else {
gameObject.GetComponent<Text>().text = WebViewSample.GetComponent<WebViewSample>().GetURL();
gameObject.GetComponent<Text>().text += " を表示中";
}
}
}
デバイスでの動作確認
このように、表示中のURLや更新状態を正しく表示することができました。
おわりに
Webview 上のユーザー操作は、Webview経由で取得するしかありません。そして、コールバックもどういう順序でコールされるかなどAndroidとiOSで振る舞いも異なり非常に苦労しました。ただ、手探りで実験的ではありましたが、何とか動いているようです。
もし、こうした方がよいなどコメントで教えていただけると非常にありがたいです。
コメント
[…] 【Unity】 WebView を狙った位置に表示する今回はUnityで WebView でのWebページ表示を2DのRectTransformで構成されたUIの中に埋め込んでキレイに表示する方法について説明します。WebViewはグリーさんから公開いただいているアセット unity…hirokuma.blog2021.03.09 【Unity】 WebView で表示状態とURLを取得するUnityで WebView を使うにあたって、… […]
very nice blog
af62fod23441k83b