概要
- ReactNativeのアプリでWebViewを使う時に、Reactの世界とWebViewの世界でデータのやり取りをする方法を調べたのでそれの紹介
本題
WebViewとは
- スマホアプリの中にWebページを表示する仕組み
ReactNativeのWebView
- ReactNativeでは
WebView
というコンポーネントが用意されている -
WebView
コンポーネントにURLを属性で渡すとアプリでWebページを表示できるようになる - ViewとかTextとかのコンポーネントと同じ感覚で配置するだけで使える
何をやりたいのか
- アプリの中にWebViewを埋め込む時に相互にデータのやりとりをしたい
- WebView内で入力した情報をアプリ側で使用したいとか
- アプリ側で持っている情報をWebView内に埋め込みたいとか
アプリ->WebView
- アプリからWebViewに情報を渡す方法
やり方
- アプリからWebViewへJavaScriptのコードを渡して実行できる
- 以下の2パターンがある
WebView作成時に渡すパターン
- WebViewに
injectedjavascript
という属性でJavaScriptのコードを渡す
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作成後に実行するパターン
- WebViewのrefに対して
injectjavascript
を実行すると引数で渡したJavaScriptが実行される
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.