WebviewBridgeとは
ReactNativeに限らずiPhoneやAndroidなどさまざまなアプリケーションやソフトウェアでブラウザをコンポーネントとして使いたい場面は多い。
特にスマホアプリでは、ガワネイティブと呼ばれる外側をネイティブなアプリケーションとして開発して、内側の実装をウェブページとして実装することが多い。
そういう場合にアプリ内にブラウザをコンポーネントとして取り込んで、外側と内側で情報のやりとりやイベントの呼び出しなどを行うこと目的としてWebviewBridgeの実装が用意される。
ウェブサイトの開発の方が経験者が豊富とか、過去の資産をそのまま活かしたりできるという特徴もあるし、アプリのデプロイをしなくてもサーバ側で情報を変更するだけで表示を変えられるといったメリットがある。
実現方法
基本的にはブラウザ側のjavascriptとアプリ側のコードが簡単な文字列を送受信する形で実装されることが多い。何でもできると逆にセキュリティホールになる可能性が高いため基本的にはあまり複雑なことはできないのが一般的。
Androidやiosでもwebviewにjavascriptを呼び出してブラウザ側から値を取得するような処理は用意されている。
ReactNativeでは
ReactNativeの基本的なことは置いておいて、bridge可能な実装として下記がメジャー
https://github.com/alinz/react-native-webview-bridge
このサンプルコードをいじってみて挙動がどの程度正確か探ってみる。ちなみに、
npm i react-native-webview-bridge
でインストールされるバージョンはちょっと古いのでgithubを直接指定して使う必要がある。今回はサンプルアプリを弄りたいので
git clone git@github.com:alinz/react-native-webview-bridge.git
して、且つそのままだとサンプルのpackage.jsonのreact-nativeのverが低いので
"react-native": "^0.24.0",
に変更してからnpm i
しました。
iPhoneの場合
サンプルコードを弄って、どの処理がどのタイミングで表示されるのかを確認するアプリを作成して、次の3つの項目について確認する。
- WebBridgeが有効か?
- urlのstateが変更したタイミングでページが更新されるか?
- ネイティブ側と通信できるか?
- DOMContentLoaded:ページの読み込みが終わったタイミング
- Injection from Lib:ライブラリの内部実装でJSが注入されたタイミング
- EventListen:ブラウザ側がJSが注入されたことを確認したタイミング
- Injection from Lib End:JSの注入が完了したタイミング
- Injection from app.js:React側から任意のJSが注入されたタイミング
iPhone実装を確認した限り想定通りに処理が進んでいることが確認できた。
加えて、一番上のログが'Test2'となっているがWebview内でstateをchangeする形でTest2というページに遷移しても問題なくBridge処理が進んでいることが確認できた。
- hoge:ReactNative側の送信が押されたタイミングでブラウザ側に文字列'hoge'が通知されたタイミング
送信ボタンを押す度にhogeが表示されるのでBridgeが構築されていることも確認できた。
Androidの場合
EventListenが表示されないのでブラウザ側にEventが発行されないことがわかる。これではブラウザ側から通信が可能かどうかの判断ができない。
実装を確認すると、すでにwindow.WebViewBridge
が存在してjsの注入作業が進んでいないことがわかる。
なぜ、そのようなことが起きてしまうのかは後々調べるとして、ひとまず処理を通過させるために、ページ側にwindow.WebViewBridge = null;
を追加してページが読み込まれた瞬間にnullを突っ込んでみる。
app.jsのタイミングがおかしいがとりあえずEventが発行されることは確認された。
iPhoneと同様にhogeが出力されるのでアプリとwebview間でも通信できることは確認できた。
結論
ひとまず、window.WebViewBridge = null;
をページ側に書いておこう。こうすればAndroidとiPhoneで動作するものは作れそう。ただし、まだそれでもAndroidは不安定な印象。
なぜそのようなことになるのかは、ライブラリについてはこれから調査していく。
続報を待て!