Browse Source

refactor index.ios.js with using postMessage

iou90 5 years ago
parent
commit
5e8d98fade
3 changed files with 82 additions and 85 deletions
  1. 32
    10
      autoHeightWebView/common.js
  2. 48
    73
      autoHeightWebView/index.ios.js
  3. 2
    2
      demo/config.js

+ 32
- 10
autoHeightWebView/common.js View File

109
 }
109
 }
110
 
110
 
111
 export function isSizeChanged(height, oldHeight, width, oldWidth) {
111
 export function isSizeChanged(height, oldHeight, width, oldWidth) {
112
-  return (height && height !== oldHeight) || (width && width !== oldWidth);
112
+  if (height == null || width == null) {
113
+    return false;
114
+  }
115
+  return height !== oldHeight || width !== oldWidth;
113
 }
116
 }
114
 
117
 
115
 export const domMutationObserveScript = `
118
 export const domMutationObserveScript = `
121
 });
124
 });
122
 `;
125
 `;
123
 
126
 
124
-export const getCurrentSize = `
125
-function getSize(container) {
126
-  var height = container.offsetHeight || document.body.offsetHeight;
127
-  var width = container.offsetWidth || document.body.offsetWidth;
128
-  return {
129
-    height: height,
130
-    width: width
131
-  };
127
+export function updateSizeWithMessage(element) {
128
+  return `
129
+  var updateSizeInterval = null;
130
+  var height = 0;
131
+  function updateSize() {
132
+    if (!window.hasOwnProperty('ReactNativeWebView') || !window.ReactNativeWebView.hasOwnProperty('postMessage')) {
133
+      !updateSizeInterval && (updateSizeInterval = setInterval(updateSize, 200));
134
+      return;
135
+    }
136
+    height = ${element}.offsetHeight || window.innerHeight,
137
+    width = ${element}.offsetWidth || window.innerWidth;
138
+    window.ReactNativeWebView.postMessage(JSON.stringify({ width: width, height: height }));
139
+  }
140
+  `;
141
+}
142
+
143
+export function getStateFromProps(props, state) {
144
+  const { height: oldHeight, width: oldWidth } = state;
145
+  const height = props.style ? props.style.height : null;
146
+  const width = props.style ? props.style.width : null;
147
+  if (isSizeChanged(height, oldHeight, width, oldWidth)) {
148
+    return {
149
+      height: height || oldHeight,
150
+      width: width || oldWidth,
151
+      isSizeChanged: true
152
+    };
153
+  }
154
+  return null;
132
 }
155
 }
133
-`;

+ 48
- 73
autoHeightWebView/index.ios.js View File

17
   isSizeChanged,
17
   isSizeChanged,
18
   handleSizeUpdated,
18
   handleSizeUpdated,
19
   domMutationObserveScript,
19
   domMutationObserveScript,
20
-  getCurrentSize
20
+  getStateFromProps,
21
+  updateSizeWithMessage
21
 } from './common.js';
22
 } from './common.js';
22
 
23
 
23
 import momoize from './momoize';
24
 import momoize from './momoize';
61
   getUpdatedState = momoize(setState, isEqual);
62
   getUpdatedState = momoize(setState, isEqual);
62
 
63
 
63
   static getDerivedStateFromProps(props, state) {
64
   static getDerivedStateFromProps(props, state) {
64
-    const { height: oldHeight, width: oldWidth } = state;
65
-    const height = props.style ? props.style.height : null;
66
-    const width = props.style ? props.style.width : null;
67
-    if (isSizeChanged(height, oldHeight, width, oldWidth)) {
68
-      return {
69
-        height: height || oldHeight,
70
-        width: width || oldWidth,
71
-        isSizeChanged: true
72
-      };
73
-    }
74
-    return null;
65
+    return getStateFromProps(props, state);
75
   }
66
   }
76
 
67
 
77
   componentDidUpdate() {
68
   componentDidUpdate() {
92
     }
83
     }
93
   }
84
   }
94
 
85
 
95
-  handleNavigationStateChange = navState => {
96
-    const { title } = navState;
97
-    const { onNavigationStateChange } = this.props;
98
-    if (!title) {
99
-      onNavigationStateChange && onNavigationStateChange(navState);
86
+  onMessage = event => {
87
+    if (!event.nativeEvent) {
100
       return;
88
       return;
101
     }
89
     }
102
-    const [heightValue, widthValue] = title.split(',');
103
-    const width = Number(widthValue);
104
-    const height = Number(heightValue);
90
+    let data = {};
91
+    // Sometimes the message is invalid JSON, so we ignore that case
92
+    try {
93
+      data = JSON.parse(event.nativeEvent.data);
94
+    } catch (error) {
95
+      console.error(error);
96
+      return;
97
+    }
98
+    const { height, width } = data;
105
     const { height: oldHeight, width: oldWidth } = this.state;
99
     const { height: oldHeight, width: oldWidth } = this.state;
106
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
100
     if (isSizeChanged(height, oldHeight, width, oldWidth)) {
107
       this.props.enableAnimation && this.opacityAnimatedValue.setValue(0);
101
       this.props.enableAnimation && this.opacityAnimatedValue.setValue(0);
111
         width
105
         width
112
       });
106
       });
113
     }
107
     }
114
-    onNavigationStateChange && onNavigationStateChange(navState);
108
+    const { onMessage } = this.props;
109
+    onMessage && onMessage(event);
115
   };
110
   };
116
 
111
 
117
   stopLoading() {
112
   stopLoading() {
128
       decelerationRate,
123
       decelerationRate,
129
       allowsInlineMediaPlayback,
124
       allowsInlineMediaPlayback,
130
       dataDetectorTypes,
125
       dataDetectorTypes,
131
-      onMessage,
126
+      onNavigationStateChange,
132
       onError,
127
       onError,
133
       onLoad,
128
       onLoad,
134
       onLoadStart,
129
       onLoadStart,
161
           dataDetectorTypes={dataDetectorTypes}
156
           dataDetectorTypes={dataDetectorTypes}
162
           originWhitelist={originWhitelist || ['*']}
157
           originWhitelist={originWhitelist || ['*']}
163
           ref={this.webView}
158
           ref={this.webView}
164
-          onMessage={onMessage}
159
+          onMessage={this.onMessage}
165
           onError={onError}
160
           onError={onError}
166
           onLoad={onLoad}
161
           onLoad={onLoad}
167
           onLoadStart={onLoadStart}
162
           onLoadStart={onLoadStart}
171
           scrollEnabled={!!scrollEnabled}
166
           scrollEnabled={!!scrollEnabled}
172
           injectedJavaScript={script}
167
           injectedJavaScript={script}
173
           source={source}
168
           source={source}
174
-          onNavigationStateChange={this.handleNavigationStateChange}
169
+          onNavigationStateChange={onNavigationStateChange}
175
         />
170
         />
176
       </Animated.View>
171
       </Animated.View>
177
     );
172
     );
190
 
185
 
191
 // add viewport setting to meta for WKWebView
186
 // add viewport setting to meta for WKWebView
192
 const commonScript = `
187
 const commonScript = `
193
-    var meta = document.createElement('meta'); 
194
-    meta.setAttribute('name', 'viewport'); 
195
-    meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);
196
-    updateSize();
197
-    window.addEventListener('load', updateSize);
198
-    window.addEventListener('resize', updateSize);
199
-    `;
188
+var meta = document.createElement('meta'); 
189
+meta.setAttribute('name', 'viewport'); 
190
+meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);
191
+updateSize();
192
+window.addEventListener('load', updateSize);
193
+window.addEventListener('resize', updateSize);
194
+`;
200
 
195
 
201
 function getBaseScript(style) {
196
 function getBaseScript(style) {
202
   return `
197
   return `
203
-    ;
204
-    ${getCurrentSize}
205
-    (function () {
206
-      if (!document.getElementById("rnahw-wrapper")) { 
207
-          var height = 0;
208
-          var width = ${getWidth(style)};
209
-          var wrapper = document.createElement('div');
210
-          wrapper.id = 'rnahw-wrapper';
211
-          while (document.body.firstChild instanceof Node) {
212
-              wrapper.appendChild(document.body.firstChild);
213
-          }
214
-          document.body.appendChild(wrapper);
215
-          function updateSize() {
216
-            if (document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
217
-               var size = getSize(wrapper);
218
-               height = size.height;
219
-               width = size.width;
220
-               document.title = height.toString() + ',' + width.toString();
221
-            }
222
-          }
223
-        ${commonScript}
224
-        ${domMutationObserveScript}
225
-        }
226
-    } ());
227
-    `;
198
+  ;
199
+  (function () {
200
+    if (!document.getElementById("rnahw-wrapper")) {
201
+      var wrapper = document.createElement('div');
202
+      wrapper.id = 'rnahw-wrapper';
203
+      wrapper.appendChild(document.body.firstChild);
204
+      document.body.appendChild(wrapper);
205
+    }
206
+    var width = ${getWidth(style)};
207
+    ${updateSizeWithMessage('wrapper')}
208
+    ${commonScript}
209
+    ${domMutationObserveScript}
210
+  } ());
211
+  `;
228
 }
212
 }
229
 
213
 
230
 function getIframeBaseScript(style) {
214
 function getIframeBaseScript(style) {
231
   return `
215
   return `
232
-    ;
233
-    ${getCurrentSize}
234
-    (function () {
235
-        var height = 0;
236
-        var width = ${getWidth(style)};
237
-        function updateSize() {
238
-            if(document.body.offsetHeight !== height || document.body.offsetWidth !== width) {
239
-                var size = getSize(document.body.firstChild);
240
-                height = size.height;
241
-                width = size.width;
242
-                document.title = height.toString() + ',' + width.toString();
243
-            }
244
-        }
245
-        ${commonScript}
246
-        ${domMutationObserveScript}
247
-    } ());
248
-    `;
216
+  ;
217
+  (function () {
218
+    var width = ${getWidth(style)};
219
+    ${updateSizeWithMessage('document.body.firstChild')}
220
+    ${commonScript}
221
+    ${domMutationObserveScript}
222
+  } ());
223
+  `;
249
 }
224
 }

+ 2
- 2
demo/config.js View File

28
 
28
 
29
 //https://medium.com/@elhardoum/opening-external-links-in-browser-in-react-native-webview-18fe6a66312a
29
 //https://medium.com/@elhardoum/opening-external-links-in-browser-in-react-native-webview-18fe6a66312a
30
 const autoDetectLinkScript = `
30
 const autoDetectLinkScript = `
31
-!function(){
31
+(function(){
32
   function isUrl(str){
32
   function isUrl(str){
33
     return str.startsWith('http');
33
     return str.startsWith('http');
34
   }
34
   }
35
   var e=function(e,n,t){if(n=n.replace(/^on/g,""),"addEventListener"in window)e.addEventListener(n,t,!1);else if("attachEvent"in window)e.attachEvent("on"+n,t);else{var o=e["on"+n];e["on"+n]=o?function(e){o(e),t(e)}:t}return e},n=document.querySelectorAll("a[href]");if(n)for(var t in n)n.hasOwnProperty(t)&&e(n[t],"onclick",function(e){!isUrl(this.href)||(e.preventDefault(),window.postMessage(JSON.stringify({url:this.href})))})
35
   var e=function(e,n,t){if(n=n.replace(/^on/g,""),"addEventListener"in window)e.addEventListener(n,t,!1);else if("attachEvent"in window)e.attachEvent("on"+n,t);else{var o=e["on"+n];e["on"+n]=o?function(e){o(e),t(e)}:t}return e},n=document.querySelectorAll("a[href]");if(n)for(var t in n)n.hasOwnProperty(t)&&e(n[t],"onclick",function(e){!isUrl(this.href)||(e.preventDefault(),window.postMessage(JSON.stringify({url:this.href})))})
36
-}();
36
+}());
37
 `;
37
 `;
38
 
38
 
39
 const autoHeightScript = `
39
 const autoHeightScript = `