ReactNativeのWebviewBridgeがどれくらいちゃんと動くか試してみた

# 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が変更したタイミングでページが更新されるか？
- ネイティブ側と通信できるか？

![Cursor_と_iPhone_6_-_iPhone_6___iOS_9_3__13E230_.png](https://qiita-image-store.s3.amazonaws.com/0/53041/fa866644-3eaa-285e-9af5-27bc150c140b.png)

- **DOMContentLoaded**：ページの読み込みが終わったタイミング
- **Injection from Lib**：ライブラリの内部実装でJSが注入されたタイミング
- **EventListen**：ブラウザ側がJSが注入されたことを確認したタイミング
- **Injection from Lib End**：JSの注入が完了したタイミング
- **Injection from app.js**：React側から任意のJSが注入されたタイミング

iPhone実装を確認した限り想定通りに処理が進んでいることが確認できた。

![Cursor_と_iPhone_6_-_iPhone_6___iOS_9_3__13E230_.png](https://qiita-image-store.s3.amazonaws.com/0/53041/8851a39e-be1b-c1d1-70ea-8f47d44ae003.png)

加えて、一番上のログが'Test2'となっているがWebview内でstateをchangeする形でTest2というページに遷移しても問題なくBridge処理が進んでいることが確認できた。

- **hoge**：ReactNative側の送信が押されたタイミングでブラウザ側に文字列'hoge'が通知されたタイミング

送信ボタンを押す度にhogeが表示されるのでBridgeが構築されていることも確認できた。

# Androidの場合

![Screenshot_2016-06-09-11-44-25.png](https://qiita-image-store.s3.amazonaws.com/0/53041/0c1f339e-59f0-ca25-30e2-54f1e907bd3c.png)

EventListenが表示されないのでブラウザ側にEventが発行されないことがわかる。これではブラウザ側から通信が可能かどうかの判断ができない。

![Cursor_と_WebViewBridgeManager_java_—__Users_yositosi_public_node_react-native-webview-bridge_examples_SampleRN20.png](https://qiita-image-store.s3.amazonaws.com/0/53041/dc1e4989-d1f7-a34b-0ddf-7825de8af83c.png)

実装を確認すると、すでに`window.WebViewBridge`が存在してjsの注入作業が進んでいないことがわかる。

![Cursor_と_test_html_—_SampleRN20_—__Users_yositosi_public_node_react-native-webview-bridge_examples_SampleRN20.png](https://qiita-image-store.s3.amazonaws.com/0/53041/ada9299f-dae1-5b68-3b2c-e3d4b09da7ba.png)

なぜ、そのようなことが起きてしまうのかは後々調べるとして、ひとまず処理を通過させるために、ページ側に`window.WebViewBridge = null;`を追加してページが読み込まれた瞬間にnullを突っ込んでみる。

![Screenshot_2016-06-10-14-14-53.png](https://qiita-image-store.s3.amazonaws.com/0/53041/ad6669c2-1b86-ec8c-7663-46a42690f0bf.png)

app.jsのタイミングがおかしいがとりあえずEventが発行されることは確認された。

![Screenshot_2016-06-10-14-15-01.png](https://qiita-image-store.s3.amazonaws.com/0/53041/8bfff432-83b4-6e63-942c-5535cd9df2c7.png)

iPhoneと同様にhogeが出力されるのでアプリとwebview間でも通信できることは確認できた。

# 結論
ひとまず、`window.WebViewBridge = null;`をページ側に書いておこう。こうすればAndroidとiPhoneで動作するものは作れそう。ただし、まだそれでもAndroidは不安定な印象。
なぜそのようなことになるのかは、ライブラリについてはこれから調査していく。

続報を待て！