rrrtcdish2’s diary

Webエンジニアの技術日記です。たまに趣味のパデルや旅行について書いていきます。

移転しました。

約3秒後に自動的にリダイレクトします。

次のURLはこちら↓↓

WebView内での特定URL遷移時にアプリブラウザで表示させる方法

はじめに

Androidアプリ開発時にWebView内で特定のURLをタップされたときに、アプリの標準ブラウザで表示させるという対応をしたので、記事として書きたいと思います!

ちなみに今回の特定のURLというのは、最初にWebViewで開いたURLとドメインが違った場合です。

例えば

  1. WebView.loadUrlで https://google.com を開いたとします。

  2. 次にWebView内で https://google.co.jp を開く。

  3. ここで 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 viewview.getUrl() でWebViewがスタートしたURLを取得可能

WebResourceRequest requestrequest.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メソッドが二回呼ばれるという症状が発生。。。バグみたいな動きなので当然修正。

具体的には

  1. WebView開く
  2. WebViewで外部ドメインのリンクをタップ
  3. ブラウザ起動
  4. アプリに戻るともう一度呼ばれてまたブラウザ起動。。。

改善したコード

結構強引だけど、一番最初にブラウザ起動した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;
  }
}

参考元 

www.jaga.biz

stackoverflow.com

qiita.com