Browse Source

chore(docs): Added guides for communication between React Native and web pages (#377)

* Added guides for communication between React Native and web pages

* Updated Guide a bit
Jamon Holmgren 5 years ago
parent
commit
2260690810
2 changed files with 152 additions and 0 deletions
  1. 146
    0
      docs/Guide.md
  2. 6
    0
      docs/Reference.md

+ 146
- 0
docs/Guide.md View File

@@ -8,6 +8,10 @@ _This guide is currently a work in progress._
8 8
 
9 9
 - [Basic Inline HTML](Guide.md#basic-inline-html)
10 10
 - [Basic URL Source](Guide.md#basic-url-source)
11
+- [Controlling navigation state changes](Guide.md#controlling-navigation-state-changes)
12
+- [Add support for File Upload](Guide.md#add-support-for-file-upload)
13
+- [Add support for File Download](Guide.md#add-support-for-file-download)
14
+- [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
11 15
 
12 16
 ### Basic inline HTML
13 17
 
@@ -180,6 +184,7 @@ Save to gallery:
180 184
 ##### Android
181 185
 
182 186
 Add permission in AndroidManifest.xml:
187
+
183 188
 ```xml
184 189
 <manifest ...>
185 190
   ......
@@ -190,3 +195,144 @@ Add permission in AndroidManifest.xml:
190 195
   ......
191 196
 </manifest>
192 197
 ```
198
+
199
+### Communicating between JS and Native
200
+
201
+You will often find yourself wanting to send messages to the web pages loaded by your webviews and also receiving messages back from those web pages.
202
+
203
+To accomplish this, React Native WebView exposes three different options:
204
+
205
+1. React Native -> Web: The `injectedJavaScript` prop
206
+2. React Native -> Web: The `injectJavaScript` method
207
+3. Web -> React Native: The `postMessage` method and `onMessage` prop
208
+
209
+#### The `injectedJavaScript` prop
210
+
211
+This is a script that runs immediately after the web page loads for the first time. It only runs once, even if the page is reloaded or navigated away.
212
+
213
+```jsx
214
+import React, { Component } from "react";
215
+import { View } from "react-native";
216
+import { WebView } from "react-native-webview";
217
+
218
+export default class App extends Component {
219
+  render() {
220
+    const runFirst = `
221
+      document.body.style.backgroundColor = 'red';
222
+      setTimeout(function() { window.alert('hi') }, 2000);
223
+      true; // note: this is required, or you'll sometimes get silent failures
224
+    `;
225
+    return (
226
+      <View style={{ flex: 1 }}>
227
+        <WebView
228
+          source={{
229
+            uri:
230
+              "https://github.com/react-native-community/react-native-webview"
231
+          }}
232
+          injectedJavaScript={runFirst}
233
+        />
234
+      </View>
235
+    );
236
+  }
237
+}
238
+```
239
+
240
+This runs the JavaScript in the `runFirst` string once the page is loaded. In this case, you can see that both the body style was changed to red and the alert showed up after 2 seconds.
241
+
242
+<img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
243
+
244
+*Under the hood*
245
+
246
+> On iOS, `injectedJavaScript` runs a method on WKWebView called `evaluateJavaScript:completionHandler:`
247
+> On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
248
+
249
+#### The `injectJavaScript` method
250
+
251
+While convenient, the downside to the previously mentioned `injectedJavaScript` prop is that it only runs once. That's why we also expose a method on the webview ref called `injectJavaScript` (note the slightly different name!).
252
+
253
+```jsx
254
+import React, { Component } from "react";
255
+import { View } from "react-native";
256
+import { WebView } from "react-native-webview";
257
+
258
+export default class App extends Component {
259
+  render() {
260
+    const run = `
261
+      document.body.style.backgroundColor = 'blue';
262
+      true;
263
+    `;
264
+
265
+    setTimeout(() => {
266
+      this.webref.injectJavaScript(run);
267
+    }, 3000);
268
+
269
+    return (
270
+      <View style={{ flex: 1 }}>
271
+        <WebView
272
+          ref={r => (this.webref = r)}
273
+          source={{
274
+            uri:
275
+              "https://github.com/react-native-community/react-native-webview"
276
+          }}
277
+        />
278
+      </View>
279
+    );
280
+  }
281
+}
282
+```
283
+
284
+After 3 seconds, this code turns the background blue:
285
+
286
+<img alt="Screenshot of app showing injected javascript" width="200" src="https://user-images.githubusercontent.com/1479215/53670433-93a98280-3c2f-11e9-85a5-0e4650993817.png" />
287
+
288
+*Under the hood*
289
+
290
+> On iOS, `injectJavaScript` calls WKWebView's `evaluateJS:andThen:`
291
+> On Android, `injectJavaScript` calls Android WebView's `evaluateJavascriptWithFallback` method
292
+
293
+#### The `window.ReactNativeWebView.postMessage` method and `onMessage` prop
294
+
295
+Being able to send JavaScript to the web page is great, but what about when the web page wants to communicate back to your React Native code? This where `window.ReactNativeWebView.postMessage` and the `onMessage` prop come in.
296
+
297
+You _must_ set `onMessage` or the `window.ReactNativeWebView.postMessage` method will not be injected into the web page.
298
+
299
+`window.ReactNativeWebView.postMessage` only accepts one argument which must be a string.
300
+
301
+```jsx
302
+import React, { Component } from "react";
303
+import { View } from "react-native";
304
+import { WebView } from "react-native-webview";
305
+
306
+export default class App extends Component {
307
+  render() {
308
+    const html = `
309
+      <html>
310
+      <head></head>
311
+      <body>
312
+        <script>
313
+          setTimeout(function () {
314
+            window.ReactNativeWebView.postMessage("Hello!")
315
+          }, 2000)
316
+        </script>
317
+      </body>
318
+      </html>
319
+    `;
320
+
321
+    return (
322
+      <View style={{ flex: 1 }}>
323
+        <WebView
324
+          source={{ html }}
325
+          onMessage={event => {
326
+            alert(event.nativeEvent.data);
327
+          }}
328
+        />
329
+      </View>
330
+    );
331
+  }
332
+}
333
+```
334
+
335
+This code will result in this alert:
336
+
337
+<img alt="Alert showing communication from web page to React Native" width="200" src="https://user-images.githubusercontent.com/1479215/53671269-7e822300-3c32-11e9-9937-7ddc34ba8af3.png" />
338
+

+ 6
- 0
docs/Reference.md View File

@@ -109,6 +109,8 @@ Set this to provide JavaScript that will be injected into the web page when the
109 109
 | ------ | -------- |
110 110
 | string | No       |
111 111
 
112
+To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
113
+
112 114
 ---
113 115
 
114 116
 ### `mediaPlaybackRequiresUserAction`
@@ -329,6 +331,8 @@ Function that is invoked when the webview calls `window.ReactNativeWebView.postM
329 331
 | -------- | -------- |
330 332
 | function | No       |
331 333
 
334
+To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
335
+
332 336
 ---
333 337
 
334 338
 ### `onNavigationStateChange`
@@ -892,6 +896,8 @@ injectJavaScript('... javascript string ...');
892 896
 
893 897
 Executes the JavaScript string.
894 898
 
899
+To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide.
900
+
895 901
 ## Other Docs
896 902
 
897 903
 Also check out our [Getting Started Guide](Getting-Started.md) and [In-Depth Guide](Guide.md).