React Native で WebView を非遷移に特定の外部リンクをブラウザで開く

はじめに

実務にて、React Native + Expo CLI で WebView を非遷移に特定の外部リンクをブラウザで開いてほしいという小仕事の依頼があり、アプリ起動後、外部リンクの初回タップのみ stopLoading() が動作せずに WebView が遷移してしまう問題も含めて解決した情報になります。

ソースコード

onShouldStartLoadWithRequest = {e => {
  if (e.url == 'about:blank') return true
  else if (e.url.match('xxx')) Linking.openURL(e.url)
  else return true
}}

検証環境

解説

アプリ起動後、外部リンクの初回タップのみ stopLoading() が動作しない元々のソースコードは、下記のように WebViewonNavigationStateChange 属性に処理を記述していました。

onNavigationStateChange={e => {
  if (e.url.match('xxx')) {
    this.state.configView.stopLoading()
    Linking.openURL(e.url)
    this.setState({configStopLoadingFlag: true})
  } else this.setState({configStopLoadingFlag: false})
}}

しかし、onNavigationStateChange 属性は Android と iOS で WebView の挙動が違っており、且つ、react-native-webviewIssues にある MIGRATED: WebView stopLoading no longer working in onNavigationStateChange on Android (#15679) #8 を読むと stopLoading() が微妙な動きをすることがわかります。

そこで、onShouldStartLoadWithRequest 属性に処理を記述して対応しました。

onShouldStartLoadWithRequest = {e => {
  if (e.url == 'about:blank') return true
  else if (e.url.match('xxx')) Linking.openURL(e.url)
  else return true
}}

onShouldStartLoadWithRequest 属性は最初の読み込みで呼ばれるので、何もしないように URL を 空白ページ(about:blank)で判定します。

if (e.url == 'about:blank') return true

あとは match メソッドで特定の URL を判定、LinkingopenURL() メソッドで URL をブラウザアプリで開かせるだけです。

else if (e.url.match('xxx')) Linking.openURL(e.url)
else return true

以上です。

おわりに

React Native と Expo CLI は日本語の二次情報が少ないので、一次情報をしっかりと理解して、時には不具合を回避する為に今回のような Hack をする必要があります。