WebViewのサードパーティライブラリにInAppWebView というのがあります。
WebView内のリンクをクリックした際に、デフォルトのブラウザを開く等、なにかしら処理をしたいことがあると思います。
これまではJavaScriptを使ったりして頑張る必要があったのですが、JavaScriptをつかわずにリンクのクリックをフックする方法を解説します。
2021年10月の最新バージョンは5.3.2です。
Webページはパターンが多すぎるので抜け漏れがあるかもしれない点は気をつけてください🙏🏻
onCreateWindow
と shouldOverrideUrlLoading
2箇所で処理を書く必要があります。
onCreateWindow
onCreateWindow
はWindowが生成される際に呼ばれます。
なんらかの処理をして、読み込みを中断する場合は Future<bool>.value(true);
を呼び出してWebView自体のロードを中断するようにしましょう。
shouldOverrideUrlLoading
shouldOverrideUrlLoading
はページ読み込みの際に呼ばれます。
有効にするにはまず crossPlatform
のオプション経由でonにします。
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
),
このコールバックはリダイレクトや、iframe等のページ内の複数に読み込みに反応してしまいます。
そのためユーザのクリックによる読み込みなのか、自動的に読み込まれたのかを判定する必要があります。
AndroidはandroidHasGesture
で判定します。
ただしAndroid7.0(API Level 24)以上しか正確に動作しないので注意してください。
iOSは navigationAction.iosWKNavigationType
が IOSWKNavigationType.LINK_ACTIVATED
かどうかを判定します。
onCreateWindow
同様に読み込みを中断する場合はNavigationActionPolicy.ALLOW
をreturnしましょう。
コード
InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse(announcement.webUrl)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
),
),
onCreateWindow: (InAppWebViewController controller,
CreateWindowAction onCreateWindowAction) async {
final url = onCreateWindowAction.request.url;
if (url != null) {
final isOpened =
await ref.read(_viewModel.notifier).openBrowser(url.toString());
if (isOpened) {
return Future<bool>.value(true);
}
}
return Future<bool>.value(true);
},
shouldOverrideUrlLoading: (controller, navigationAction) async {
// リンククリックイベントのみ
if ((isIos &&
navigationAction.iosWKNavigationType !=
IOSWKNavigationType.LINK_ACTIVATED) ||
(isAndroid && !(navigationAction.androidHasGesture ?? true))) {
return NavigationActionPolicy.ALLOW;
}
final url = navigationAction.request.url;
if (url != null) {
final isOpened =
await ref.read(_viewModel.notifier).openBrowser(url.toString());
if (isOpened) {
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
);
WebViewではなく、デフォルトのブラウザで開きたい場合はurl_launcher などのライブラリを使って開くと良いと思います。