【Unity】Webviewの実装(Android、iOS対応)
本記事で扱うUnityのバージョンは「Unity2018.3.7f1」です。
UnityでのWebviewのライブラリというと、
greeさんの「unity-webview」
github.com
もしくは、AssetStoreで配信されている「UniWebView」を使用されていると思います。
https://www.assetstore.unity3d.com/jp/?stay#!/content/92605
今回はgreeさんの「unity-webview」を使用して、
サンプルを作成したので使い方や解説を行っていきます。
実装例
github.com基本はサンプル通りに処理を書いています。
ただ少し違うのが、WebView内で選択したリンクをそのままUnity側に送って、
Unity側で処理するようにしています。
Android
Android PluginのCWebViewPlugin.javaのshouldOverrideUrlLoading内の処理を一部修正しています。
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { canGoBack = webView.canGoBack(); canGoForward = webView.canGoForward(); // if (url.startsWith("http://") || url.startsWith("https://") // || url.startsWith("file://") || url.startsWith("javascript:")) { // // Let webview handle the URL // return false; // } else if (url.startsWith("unity:")) { // String message = url.substring(6); // mWebViewPlugin.call("CallFromJS", message); // return true; // } // すべてUnity側へ飛ばすように修正。 if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file://") || url.startsWith("javascript:") || url.startsWith("unity:")) { mWebViewPlugin.call("CallFromJS", url); return true; } Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); PackageManager pm = a.getPackageManager(); List<ResolveInfo> apps = pm.queryIntentActivities(intent, 0); if (apps.size() > 0) { view.getContext().startActivity(intent); } return true; }
iOS
WebView.mmのdecidePolicyForNavigationActionの処理の一部を修正しています。
- (void)webView:(WKWebView *)wkWebView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { if (webView == nil) { decisionHandler(WKNavigationActionPolicyCancel); return; } NSURL *nsurl = [navigationAction.request URL]; NSString *url = [nsurl absoluteString]; // URLの文字列が文字化けしてしまうためエンコード。 NSString *sendUrl = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]]; if ([url rangeOfString:@"//itunes.apple.com/"].location != NSNotFound) { [[UIApplication sharedApplication] openURL:nsurl]; decisionHandler(WKNavigationActionPolicyCancel); return; } else if ([url hasPrefix:@"unity:"]) { // UnitySendMessage([gameObjectName UTF8String], "CallFromJS", [[url substringFromIndex:6] UTF8String]); UnitySendMessage([gameObjectName UTF8String], "CallFromJS", [sendUrl UTF8String]); decisionHandler(WKNavigationActionPolicyCancel); return; // } else if (![url hasPrefix:@"about:blank"] // for loadHTML(), cf. #365 // && ![url hasPrefix:@"file:"] // && ![url hasPrefix:@"http:"] // && ![url hasPrefix:@"https:"] // && ![url hasPrefix:@"mailto:"] // && ![url hasPrefix:@"tel:"] // && ![url hasPrefix:@"facetime:"] // && ![url hasPrefix:@"sms:"]) { // if([[UIApplication sharedApplication] canOpenURL:nsurl]) { // [[UIApplication sharedApplication] openURL:nsurl]; // } // decisionHandler(WKNavigationActionPolicyCancel); // return; } else if (navigationAction.navigationType == WKNavigationTypeLinkActivated && (!navigationAction.targetFrame || !navigationAction.targetFrame.isMainFrame)) { // cf. for target="_blank", cf. http://qiita.com/ShingoFukuyama/items/b3a1441025a36ab7659c // [webView load:navigationAction.request]; // 全てのメッセージを送ってあげるようにする。 UnitySendMessage([gameObjectName UTF8String], "CallFromJS", [sendUrl UTF8String]); decisionHandler(WKNavigationActionPolicyCancel); return; } else { if (navigationAction.targetFrame != nil && navigationAction.targetFrame.isMainFrame) { // If the custom header is not attached, give it and make a request again. if (![self isSetupedCustomHeader:[navigationAction request]]) { NSLog(@"navi ... %@", navigationAction); [wkWebView loadRequest:[self constructionCustomHeader:navigationAction.request]]; decisionHandler(WKNavigationActionPolicyCancel); return; } } } UnitySendMessage([gameObjectName UTF8String], "CallOnStarted", [url UTF8String]); decisionHandler(WKNavigationActionPolicyAllow); }
他にもiOS側でもいくつか処理の追加を行っています。
bouncesの機能をOFFに変更
スクロールを最後まで引っ張ったときに、空白の部分まで見えてしまうやつ
画像をドラッグアンドドロップによる画像反転禁止
// bouncesをOFFに変更。 id subview = [[webView subviews] objectAtIndex:0]; if([[subview class] isSubclassOfClass:[UIScrollView class]]) { ((UIScrollView *)subview).bounces = NO; // iOS11からのドラッグアンドドロップによる画像反転禁止。 if(@available(iOS 11.0, *)) { ((UIScrollView *)subview).interactions = [[NSArray alloc] init]; } }
3DTouchの機能を無効化
// iOS10以降で3DTouchを無効にする。 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 - (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo { return false; } #endif
WebView内のテキスト選択を禁止
長押しによるメニューの表示禁止
// 読み込み完了時に呼び出される。 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { // webView内のテキスト選択禁止。 [webView evaluateJavaScript:(@"document.documentElement.style.webkitUserSelect='none';") completionHandler:^(NSString *result, NSError *error) {}]; // webView内の長押しによるメニュー表示禁止。 [webView evaluateJavaScript:(@"document.documentElement.style.webkitTouchCallout='none';") completionHandler:^(NSString *result, NSError *error) {}]; }
ここらへんの処理も追加せずに、パラメータなどで切り替えられたらいいな
もういっそUnityでAPI化してほしい!