【ReactNative】WebViewを使ってWebコンテンツを表示する
はじめに
スマホアプリを開発すると一口にいっても、その背景には色々あると思います。
個人開発なら「学習も兼ねてTODOリスト等の開発しやすいものを作ってみる」という場合もあるでしょうし、もう少し規模の大きな話になってくると「既存のWEBサービスのスマホ版を出したい」といった場合もあるかと思います。
特に後者の場合ですと、ゼロからスマホアプリを作るというよりは「今WEBにある内容」をスマホに最適化した形で落とし込む(+プッシュ通知等のスマホ固有の機能を付ける)というアプローチの開発だと思います。
WEB側がレスポンシブな場合「あれ、これそのまま使えるのでは?」といった機能や画面もあるかと思います。
分かりやすいところだと、QA画面や利用規約画面あたりはスマホアプリでもブラウザでも同じ見栄えで良さそうです。
今回はReactNative
で開発しているアプリにおいて、react-native-webview
を使うことで既に存在するWebソース
をそのまま流用する方法を紹介したいと思います。
そもそもWebViewとは
ReactNative
に限らずWebView
という言葉を聞いたことがある方は多いかと思います。
WebView
とはスマホアプリ上においてブラウザのようにWeb
コンテンツを表示させる機能です。
アプリによっては殆どの画面をWebView
で表示させているものもあれば、ピンポイントでWeb
リソースを使っている例もあり、用途は様々です。
前提条件
react@16.13.1
-
react-native@0.63.3
Typescript
を使用していきます。
インストール
yarn add react-native-webview
さらにios
の方はpod install
が必要です。
cd ios && pod install
基本編「コンテンツの表示」
まずは基本となるコンテンツの表示方法について紹介します。
HTML
を表示させるわけですが、方法は2通りあります。
①HTMLを文字列で渡す
一番オーソドックスな使い方はHTML
コンテンツを直接文字列で渡す方法です。
下記の例ではstring
型で定義した簡単なHTML
コンテンツを表示させています。
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView } from 'react-native-webview';
// WebViewで表示させるHTML
const html : string = `
<html>
<head></head>
<body>
<h1 style="font-size:56;color:red;" >Title</h1>
<p style="font-size:44px;color:blue;font-weight:bold;" >This page is html.</p>
</body>
</html>
`;
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView source={{html: html}} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
出力
スタイルの指定まで効いていることが分かります。
②URI指定
冒頭で述べた例では、こちらのパターンを利用するケースが多いと思います。
既にあるWeb
コンテンツを表示する場合はuri
として指定します。
下記の例では、Zenn
のトップページを指定しています。
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView } from 'react-native-webview';
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView source={{uri: "https://zenn.dev"}} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
出力
Zenn
はレスポンシブデザインのため、WebView
で表示しても崩れることなく表示されています。
そのままスマホアプリとして使用しても遜色ないUI
ですね。
応用編「データの授受」
ここまでで基本となるコンテンツの表示はできるようになりました。
しかしあくまで表示ができているだけで、スマホアプリ側のデータの授受ができていません。
例えば「WebView
側でボタンを押した時にReactNative
側で定義した関数を発火させる」ことや「WebView
側で行った処理結果をReactNative
側が受けとる」等を行いたい場合があると思います。
①「injectedJavaScriptでJSをWeb側に渡す」
WebView
のinjectedJavascript
というパラメータを指定することで、ReactNative
側で定義したJS
をWeb
コンテンツ側に渡すことができます。
ボタンを押した時の関数を定義して渡したい場合は、コンテンツより先にJS
が読み込まれる必要があるためinjectedJavaScriptBeforeContentLoaded
を指定します。
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView } from 'react-native-webview';
// WebViewに渡すコード
const injectedCode : string = `
function fireInjectedJavaScript(){
alert('ReactNativeから渡されたコードを実行しました!');
}
`;
// WebViewで表示させるHTML
const html : string = `
<html>
<head></head>
<body>
<form name="test">
<input type="button" value="injectedJavaScript" onClick="fireInjectedJavaScript()">
</form>
</body>
</html>
`;
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView
source={{html: html}}
injectedJavaScriptBeforeContentLoaded={injectedCode} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
出力
表示されたボタンをタップすることで、ReactNative
側から渡された関数が実行されることが確認できます。
②「onMessageでJSからReactNativeへ値を渡す」
Web
コンテンツ側から何らかの値をReactNative
に返してあげたい場合はonMessage
にイベントハンドラを指定します。
イベントで取得できる値はWebViewMessageEvent
という発火イベント情報もろもろを内包した型です。実際に渡された値はnativeEvent.data
の中に格納されています。
その上でWeb
コンテンツ側ではwindow.ReactNativeWebView.postMessage()
を実行し、渡したい値を引数に指定します。
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView, WebViewMessageEvent } from 'react-native-webview';
// WebViewに渡すコード
const injectedCode : string = `
function fireInjectedJavaScript(){
window.ReactNativeWebView.postMessage('ReactNativeから渡されたコードを実行しました!');
}
`;
// WebViewで表示させるHTML
const html : string = `
<html>
<head></head>
<body>
<form name="test">
<input type="button" value="injectedJavaScript" onClick="fireInjectedJavaScript()">
</form>
</body>
</html>
`;
// WebView側からのデータ取得イベント
const onMessageFromHtml = (event : WebViewMessageEvent) => {
// event.nativeEvent.dataの中に値が入っている
console.log(event.nativeEvent.data);
}
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView
source={{html: html}}
injectedJavaScriptBeforeContentLoaded={injectedCode}
onMessage={onMessageFromHtml} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
出力
画面に表示されたボタンを押すことで、Web
コンテンツ側からReactNative
に値が送られてログに表示されました。
LOG ReactNativeから渡されたコードを実行しました!
まとめ
今回はReactNative
のアプリ上でWeb
コンテンツを表示するライブラリであるreact-native-webview
について紹介しました。
作りたいアプリの内容によっては殆どWeb
コンテンツで賄えることもあると思います。
使い回しができる箇所はどんどん使っていくことで、開発コストを削減する効果も見込めるため非常にオススメです。
また、アプリの冒頭に表示させるキャンペーン画面等もWebView
で作成しておくと、キャンペーンが切り替わる毎にアプリのアップデートを行いストアへ公開する必要もなくなるので、そういった場面でも有用なのではないかと思います。
Discussion