JavaScript
reactnative

[React Native]ReactNativeとWebViewのデータ連携

概要

  • ReactNativeのアプリでWebViewを使う時に、Reactの世界とWebViewの世界でデータのやり取りをする方法を調べたのでそれの紹介

本題

WebViewとは

  • アプリの中にWebページを表示する仕組み

ReactNativeのWebView

  • ReactNativeではWebViewというコンポーネントが用意されている
  • WebViewコンポーネントにURLを属性で渡すとアプリでWebページを表示できるようになる
  • ViewとかTextとかのコンポーネントと同じ感覚で配置するだけで使える

何をやりたいのか

  • アプリの中にWebViewを埋め込む時に相互にデータのやりとりをしたい
    • WebView内で入力した情報をアプリ側で使用したいとか
    • アプリ側で持っている情報をWebView内に埋め込みたいとか

アプリ->WebView

  • アプリからWebViewに情報を渡す方法

やり方

  • アプリからWebViewへJavaScriptのコードを渡して実行できる
  • 以下の2パターンがある
WebView作成時に渡すパターン
const jsCode = `
const inputName = document.getElementById('input-name');
inputName.value = 'ozaki';
`
class xxx extends Components {
  render() {
    return(
      <WebView
        source={'http://localhost:8080/'}
        injectedJavaScript={jsCode}
      />
    )
  }
}
  • 渡したコードはWebView生成後に画面内に埋め込まれる
    • 上記の例では画面の描画直後に実行されて、入力域にozakiと入った状態で画面が表示される
  • JavaScriptのコードはStringで渡さなければいけないのでちょっと扱いづらい
WebView作成後に実行するパターン
const jsCode = `
const inputName = document.getElementById('input-name');
inputName.value = 'ozaki';
`
class xxx extends Component {
  someFunc() {
    this.webview.injectjavascript(jsCode)
  }
  render() {
    return(
      <WebView
        ref={ref => this.webview = ref}
        source={'http://localhost:8080/'}
      />
    )
  }
}
  • このパターンではinjectjavascriptを実行した時に渡したJavaScriptも実行される
    • 上記の例では、someFuncを呼ぶと、入力域にozakiと値が入ることになる
  • こちらもJavaScriptのコードはStringで渡さないといけない

WebView->アプリ

  • WebViewからアプリに情報を渡す方法

postMessageとonMessage

  • Webページにはwindowに対してpostMessageという関数が紐付けられている
  • このpostMessageを実行するとWebViewからアプリにデータの送信ができる
  • アプリ側はonMessageメソッドを定義することでpostMessageの送信内容を受信することができる
// ReactNative側
class xxx extends Component {
  onMessage = (event) => {
    const { data } = event.nativeEvent;
    if (data === 'OK') {
      alert('OK!');
    } else if (data === 'NG') {
      alert('NG');
    }
  };
}

// WebView側
window.postMessage('OK');
  • postMessageの引数はevent.nativeEvent.dataで取得できる
  • postMessageの引数はStringしか渡すことができない

まとめ

  • アプリとWebViewのデータ連携はあまり柔軟性がない
    • セキュリティ的な要因とかなのかな?
  • とはいえ、最低限の連携はできるので大抵のケースはこれだけできれば十分だと思う

追記

  • バージョンが上がっていつの間にかドキュメントにSecurityWarningが追加されていました

Security Warning: Currently, onMessage and postMessage do not allow specifying an origin. This can lead to cross-site scripting attacks if an unexpected document is loaded within a WebView instance. Please refer to the MDN documentation for Window.postMessage() for more details on the security implications of this.