WebView内での特定URL遷移時にアプリブラウザで表示させる方法
はじめに
Androidアプリ開発時にWebView内で特定のURLをタップされたときに、アプリの標準ブラウザで表示させるという対応をしたので、記事として書きたいと思います!
ちなみに今回の特定のURLというのは、最初にWebViewで開いたURLとドメインが違った場合です。
例えば
WebView.loadUrlで https://google.com を開いたとします。
次にWebView内で https://google.co.jp を開く。
ここで https://google.co.jp をアプリのブラウザで開く。
ということがしたいわけです。
解決方法
そもそもですが、WebView内のURLリクエストをフックするには
WebViewClient#shouldOverrideUrlLoading
というメソッドが必要です。簡単にコードを書くとこんな感じですね。
@Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { view.loadUrl(String.valueOf(request.getUrl())); return true; }
shouldOverrideUrlLoading
のメソッドの実装ができたら、次は入力されてきた引数であるWebView view
WebResourceRequest request
を比較します。
これらの値にURLの情報が含まれているので取り出していきましょう。
WebView view
は view.getUrl()
でWebViewがスタートしたURLを取得可能
WebResourceRequest request
は request.getUrl()
はユーザがタップしたリクエストのURLを取得可能
とこんなふうに取り出せます。今回やりたいこととしては ドメインの比較をしたい
のでこんなふうになります。
String domainName = Uri.parse(view.getUrl()).getHost(); if (!url.contains(domainName)) { // hogeHoge }
※手っ取り早くドメイン(ホスト名)を取り出すにはUriクラスのgetHost
メソッドを使うのが簡単だと思います
というわけで、ドメインの変更を検知できるようになったのでソースで表すとこんな感じになります。
ソース
webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { // ドメインが含まれていない場合、アプリブラウザ遷移 String domainName = Uri.parse(view.getUrl()).getHost(); String url = request.getUrl(); if (!url.contains(domainName)) { Uri uri = Uri.parse(url); Intent i = new Intent(Intent.ACTION_VIEW, uri); activity.startActivity(i); return true; } return false; } }
問題発生
上記のコードで完全にできた!勝った!と思ったのですが、なぜかshouldOverrideUrlLoading
メソッドが二回呼ばれるという症状が発生。。。バグみたいな動きなので当然修正。
具体的には
- WebView開く
- WebViewで外部ドメインのリンクをタップ
- ブラウザ起動
- アプリに戻るともう一度呼ばれてまたブラウザ起動。。。
改善したコード
結構強引だけど、一番最初にブラウザ起動したURLを記憶しといて二回目開いたときに同じだったら単純にtrue
を返すといったようにしました。
2回起動してしまう原因は環境のせいなんだろうか。。。
皆さんの参考になれば幸いです。
private String firstUrl; @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { // ドメインが含まれていない場合、アプリブラウザ遷移 String domainName = Uri.parse(view.getUrl()).getHost(); String url = request.getUrl(); if (!url.contains(domainName)) { if (TextUtils.equals(url, firstUrl)) { return true; } Uri uri = Uri.parse(url); Intent i = new Intent(Intent.ACTION_VIEW, uri); activity.startActivity(i); firstUrl = url; return true; } }