react-native-webviewを使って既存Webページを使い回す

ReactNativeを使って既存Webサービスのアプリ版を開発している場合、一部のアプリ独自の機能(例えばプッシュ通知やカメラ)を除いては既存ソースを流用できる場合があります。 例でいうと、ユーザ情報画面は既存のWebのマイページをそのまま表示するとかです。 その場合、WebViewを使うことになると思います。 ReactNativeでいうところのWebViewはreact-native-webviewを使うことになりますが、ここで問題になってくるのがReactNative側のコードとWebView側のコードの連携処理です。 先のマイページの例でいうと、WebView側のマイページ画面のソースコードにReactNative側からユーザ情報を渡してあげなければ成立しません。 今回はreact-native-webviewを導入した上で、WebViewとの値の受け渡し方法について調べました。

注意事項

この記事はQiita -【ReactNative】WebViewを使って既存資産を使い回すのリライト記事です。

前提条件

  • react-nativeでプロジェクト作成済

ライブラリインストール

今回はreact-native-webviewを使用します。

yarn add  react-native-webview

iOSのみ

pod installを行います。

cd ios && pod install

使い方

単純にWebページを表示するだけでなく、アプリとWebページ間での値の受渡しができます。 よって、ログイン画面をWebページ側で作って、ログイン後画面をアプリで実装なんてこともできます。

WebViewに値を渡す

WebViewに値を渡す場合はinjectedJavaScriptを使います。 injectedJavaScriptには文字列型でJavascriptのコードを渡せます。

WebViewComponent.tsx
import React from 'react';
import { WebView } from 'react-native-webview';

// WebViewに渡すコード
const injectedCode : string = `
    function fireInjectedJavaScript(){
        alert('ReactNativeから渡されたコードを実行しました!');
    }
`;

// WebViewで表示させるHTML
const html : string = `
      <html>
      <head>
      </head>
      <body>
        <h1>Title</h1>
        <form name="test">
            <input type="button" value="injectedJavaScript" onClick="fireInjectedJavaScript()">
        </form>
      </body>
      </html>
`;

// ...割愛

render(
    <WebView source={{html : html}} injectedJavaScript={injectedCode} />
);

html中のボタンでfireInjectedJavascript()を実行していますが、これはReactNative側から渡された関数です。 よって、アプリで表示された場合のみ特定の処理を行うような作りにすることもできます。

渡したコードはWebViewが描画された後に実行されるため、jQuerydocument.getElementByIdなんかを使ってWebView側の特定のフォームの値や表示をいじることもできます(上記のマイページの例ではこの方法を使ってユーザ情報を渡す)。

WebViewから値を貰う

逆にWebView側から何らかのデータを受け取りたい場合はonMessageを使います。

WebViewComponent2.tsx
import React from 'react';
import { WebView, WebViewMessageEvent } from 'react-native-webview';

// WebViewで表示させるHTML
const html : string = `
      <html>
      <head>
        <script>
            // WebViewが読み込まれた時にデータを送信
            window.onload = function() {
                window.ReactNativeWebView.postMessage("onload")
            };

            // 定期的に実行(ポーリングなんかに使える??)
            setInterval(function () {
                window.ReactNativeWebView.postMessage({hoge : "setInterval"})
            }, 2000)

            // 特定の処理実行時にデータを送信
            function firePostMessage(){
                window.ReactNativeWebView.postMessage("button click")
            }
        </script>
      </head>
      <body>
        <h1>Title</h1>
        
        <form name="test">
            <input type="button" value="postMessage" onClick="firePostMessage()">
        </form>
      </body>
      </html>
`;

// ...割愛

// onMessage発火時処理
public onMessageFromHtml(event : WebViewMessageEvent) {
    console.log(event.nativeEvent.data);
}

render(
    <WebView source={{html : html}} onMessage={onMessageFromHtml} />
);

上記の例ではWebView読み込み時に実行と、定期的に実行、ボタンを押した時に実行、と3パターンを盛り込んでいます。 いずれの場合もwindow.ReactNativeWebView.postMessageを実行しており、ReactNative側ではWebViewMessageEvent型で受け取ります。 渡された値自体はWebViewMessageEventnativeEvent.dataの中に格納されています。 nativeEvent.datareactBaseSyntheticEventのジェネリクスとなっているため型は自由です(setIntervalのようにオブジェクトを渡すこともできます)。

まとめ

今回はreact-natiev-webviewをインストールし、ReactNativeWebView間でのデータの受け渡し方法を紹介しました。 既存のソースを使いまわせるので非常に有効な手ではないかと思います。

SNSでシェアする