Browse Source

Adds guide for intercepting hash URL changes

Jamon Holmgren 5 years ago
parent
commit
745dc5992e
2 changed files with 63 additions and 22 deletions
  1. 61
    22
      docs/Guide.md
  2. 2
    0
      docs/Reference.md

+ 61
- 22
docs/Guide.md View File

14
 - [Add support for File Download](Guide.md#add-support-for-file-download)
14
 - [Add support for File Download](Guide.md#add-support-for-file-download)
15
 - [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
15
 - [Communicating between JS and Native](Guide.md#communicating-between-js-and-native)
16
 
16
 
17
-
18
 ### Basic inline HTML
17
 ### Basic inline HTML
19
 
18
 
20
 The simplest way to use the WebView is to simply pipe in the HTML you want to display. Note that setting an `html` source requires the [originWhiteList](Reference.md#originWhiteList) property to be set to `['*']`.
19
 The simplest way to use the WebView is to simply pipe in the HTML you want to display. Note that setting an `html` source requires the [originWhiteList](Reference.md#originWhiteList) property to be set to `['*']`.
48
 class MyWeb extends Component {
47
 class MyWeb extends Component {
49
   render() {
48
   render() {
50
     return (
49
     return (
51
-      <WebView
52
-        source={{uri: 'https://facebook.github.io/react-native/'}}
53
-      />
50
+      <WebView source={{ uri: 'https://facebook.github.io/react-native/' }} />
54
     );
51
     );
55
   }
52
   }
56
 }
53
 }
71
     return (
68
     return (
72
       <WebView
69
       <WebView
73
         ref={ref => (this.webview = ref)}
70
         ref={ref => (this.webview = ref)}
74
-        source={{uri: 'https://facebook.github.io/react-native/'}}
71
+        source={{ uri: 'https://facebook.github.io/react-native/' }}
75
         onNavigationStateChange={this.handleWebViewNavigationStateChange}
72
         onNavigationStateChange={this.handleWebViewNavigationStateChange}
76
       />
73
       />
77
     );
74
     );
87
     //   canGoForward?: boolean;
84
     //   canGoForward?: boolean;
88
     // }
85
     // }
89
     const { url } = newNavState;
86
     const { url } = newNavState;
90
-    if (!url) return
87
+    if (!url) return;
91
 
88
 
92
     // handle certain doctypes
89
     // handle certain doctypes
93
     if (url.includes('.pdf')) {
90
     if (url.includes('.pdf')) {
112
       const redirectTo = 'window.location = "' + newURL + '"';
109
       const redirectTo = 'window.location = "' + newURL + '"';
113
       this.webview.injectJavaScript(redirectTo);
110
       this.webview.injectJavaScript(redirectTo);
114
     }
111
     }
115
-  }
112
+  };
116
 }
113
 }
117
 ```
114
 ```
118
 
115
 
116
+#### Intercepting hash URL changes
117
+
118
+While `onNavigationStateChange` will trigger on URL changes, it does not trigger when only the hash URL ("anchor") changes, e.g. from `https://example.com/users#list` to `https://example.com/users#help`.
119
+
120
+You can inject some JavaScript to wrap the history functions in order to intercept these hash URL changes.
121
+
122
+```jsx
123
+<WebView
124
+  source={{ uri: someURI }}
125
+  injectedJavaScript={`
126
+    (function() {
127
+      function wrap(fn) {
128
+        return function wrapper() {
129
+          var res = fn.apply(this, arguments);
130
+          window.ReactNativeWebView.postMessage('navigationStateChange');
131
+          return res;
132
+        }
133
+      }
134
+
135
+      history.pushState = wrap(history.pushState);
136
+      history.replaceState = wrap(history.replaceState);
137
+      window.addEventListener('popstate', function() {
138
+        window.ReactNativeWebView.postMessage('navigationStateChange');
139
+      });
140
+    })();
141
+
142
+    true;
143
+  `}
144
+  onMessage={({ nativeEvent: state }) => {
145
+    if (state.data === 'navigationStateChange') {
146
+      // Navigation state updated, can check state.canGoBack, etc.
147
+    }
148
+  }}
149
+/>
150
+```
151
+
152
+Thanks to [Janic Duplessis](https://github.com/react-native-community/react-native-webview/issues/24#issuecomment-483956651) for this workaround.
153
+
119
 ### Add support for File Upload
154
 ### Add support for File Upload
120
 
155
 
121
 ##### iOS
156
 ##### iOS
123
 For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
158
 For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
124
 
159
 
125
 Photo capture:
160
 Photo capture:
161
+
126
 ```
162
 ```
127
 <key>NSCameraUsageDescription</key>
163
 <key>NSCameraUsageDescription</key>
128
 <string>Take pictures for certain activities</string>
164
 <string>Take pictures for certain activities</string>
129
 ```
165
 ```
130
 
166
 
131
 Gallery selection:
167
 Gallery selection:
168
+
132
 ```
169
 ```
133
 <key>NSPhotoLibraryUsageDescription</key>
170
 <key>NSPhotoLibraryUsageDescription</key>
134
 <string>Select pictures for certain activities</string>
171
 <string>Select pictures for certain activities</string>
135
 ```
172
 ```
136
 
173
 
137
 Video recording:
174
 Video recording:
175
+
138
 ```
176
 ```
139
 <key>NSMicrophoneUsageDescription</key>
177
 <key>NSMicrophoneUsageDescription</key>
140
 <string>Need microphone access for recording videos</string>
178
 <string>Need microphone access for recording videos</string>
143
 ##### Android
181
 ##### Android
144
 
182
 
145
 Add permission in AndroidManifest.xml:
183
 Add permission in AndroidManifest.xml:
184
+
146
 ```xml
185
 ```xml
147
 <manifest ...>
186
 <manifest ...>
148
   ......
187
   ......
173
 
212
 
174
 ### Multiple Files Upload
213
 ### Multiple Files Upload
175
 
214
 
176
-You can control __single__ or __multiple__ file selection by specifing the [`multiple`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple) attribute on your `input` element:
215
+You can control **single** or **multiple** file selection by specifing the [`multiple`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple) attribute on your `input` element:
177
 
216
 
178
 ```
217
 ```
179
 // multiple file selection
218
 // multiple file selection
190
 For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
229
 For iOS, all you need to do is specify the permissions in your `ios/[project]/Info.plist` file:
191
 
230
 
192
 Save to gallery:
231
 Save to gallery:
232
+
193
 ```
233
 ```
194
 <key>NSPhotoLibraryAddUsageDescription</key>
234
 <key>NSPhotoLibraryAddUsageDescription</key>
195
 <string>Save pictures for certain activities.</string>
235
 <string>Save pictures for certain activities.</string>
225
 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.
265
 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.
226
 
266
 
227
 ```jsx
267
 ```jsx
228
-import React, { Component } from "react";
229
-import { View } from "react-native";
230
-import { WebView } from "react-native-webview";
268
+import React, { Component } from 'react';
269
+import { View } from 'react-native';
270
+import { WebView } from 'react-native-webview';
231
 
271
 
232
 export default class App extends Component {
272
 export default class App extends Component {
233
   render() {
273
   render() {
241
         <WebView
281
         <WebView
242
           source={{
282
           source={{
243
             uri:
283
             uri:
244
-              "https://github.com/react-native-community/react-native-webview"
284
+              'https://github.com/react-native-community/react-native-webview',
245
           }}
285
           }}
246
           injectedJavaScript={runFirst}
286
           injectedJavaScript={runFirst}
247
         />
287
         />
255
 
295
 
256
 <img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
296
 <img alt="screenshot of Github repo" width="200" src="https://user-images.githubusercontent.com/1479215/53609254-e5dc9c00-3b7a-11e9-9118-bc4e520ce6ca.png" />
257
 
297
 
258
-*Under the hood*
298
+_Under the hood_
259
 
299
 
260
 > On iOS, `injectedJavaScript` runs a method on WKWebView called `evaluateJavaScript:completionHandler:`
300
 > On iOS, `injectedJavaScript` runs a method on WKWebView called `evaluateJavaScript:completionHandler:`
261
 > On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
301
 > On Android, `injectedJavaScript` runs a method on the Android WebView called `evaluateJavascriptWithFallback`
265
 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!).
305
 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!).
266
 
306
 
267
 ```jsx
307
 ```jsx
268
-import React, { Component } from "react";
269
-import { View } from "react-native";
270
-import { WebView } from "react-native-webview";
308
+import React, { Component } from 'react';
309
+import { View } from 'react-native';
310
+import { WebView } from 'react-native-webview';
271
 
311
 
272
 export default class App extends Component {
312
 export default class App extends Component {
273
   render() {
313
   render() {
286
           ref={r => (this.webref = r)}
326
           ref={r => (this.webref = r)}
287
           source={{
327
           source={{
288
             uri:
328
             uri:
289
-              "https://github.com/react-native-community/react-native-webview"
329
+              'https://github.com/react-native-community/react-native-webview',
290
           }}
330
           }}
291
         />
331
         />
292
       </View>
332
       </View>
299
 
339
 
300
 <img alt="Screenshot of app showing injected javascript" width="200" src="https://user-images.githubusercontent.com/1479215/53670433-93a98280-3c2f-11e9-85a5-0e4650993817.png" />
340
 <img alt="Screenshot of app showing injected javascript" width="200" src="https://user-images.githubusercontent.com/1479215/53670433-93a98280-3c2f-11e9-85a5-0e4650993817.png" />
301
 
341
 
302
-*Under the hood*
342
+_Under the hood_
303
 
343
 
304
 > On iOS, `injectJavaScript` calls WKWebView's `evaluateJS:andThen:`
344
 > On iOS, `injectJavaScript` calls WKWebView's `evaluateJS:andThen:`
305
 > On Android, `injectJavaScript` calls Android WebView's `evaluateJavascriptWithFallback` method
345
 > On Android, `injectJavaScript` calls Android WebView's `evaluateJavascriptWithFallback` method
313
 `window.ReactNativeWebView.postMessage` only accepts one argument which must be a string.
353
 `window.ReactNativeWebView.postMessage` only accepts one argument which must be a string.
314
 
354
 
315
 ```jsx
355
 ```jsx
316
-import React, { Component } from "react";
317
-import { View } from "react-native";
318
-import { WebView } from "react-native-webview";
356
+import React, { Component } from 'react';
357
+import { View } from 'react-native';
358
+import { WebView } from 'react-native-webview';
319
 
359
 
320
 export default class App extends Component {
360
 export default class App extends Component {
321
   render() {
361
   render() {
349
 This code will result in this alert:
389
 This code will result in this alert:
350
 
390
 
351
 <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" />
391
 <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" />
352
-

+ 2
- 0
docs/Reference.md View File

369
 url
369
 url
370
 ```
370
 ```
371
 
371
 
372
+Note that this method will not be invoked on hash URL changes (e.g. from `https://example.com/users#list` to `https://example.com/users#help`). There is a workaround for this that is described [in the Guide](Guide.md#intercepting-hash-url-changes).
373
+
372
 ---
374
 ---
373
 
375
 
374
 ### `originWhitelist`
376
 ### `originWhitelist`