Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making WebView's autoheight work for web #226

Open
Cogneter opened this issue Jun 3, 2022 · 0 comments
Open

Making WebView's autoheight work for web #226

Cogneter opened this issue Jun 3, 2022 · 0 comments

Comments

@Cogneter
Copy link

Cogneter commented Jun 3, 2022

So, over the past couple days, I've spent many hours trying to make my WebViews in React Native work in web (webpack). Thanks to this package and some elbow grease, I managed to make it work. Figured I'd leave instructions here for whoever encounters the same problems as me, to save them time.

My use case - displaying multiple WebViews on the screen (news posts with HTML markup) that need to have adaptable height (i.e. WebView height in React Native should match the post's content height). I'm using Expo with Ignite boilerplate for this project.

First things first - both react-native-webview and react-native-web-webview don't support automatic WebView height (see react-native-webview/react-native-webview#413). You already know this, otherwise you wouldn't be browsing this package.

react-native-autoheight-webview does a good job of making automatic height work for Android and iOS, but it doesn't work for Web. The reason - react-native-web-webview does not define window.ReactNativeWebView, so the call window.ReactNativeWebView.postMessage fails on Web and React Native can't receive height data from the WebView.

This can be circumvented by replacing these calls with window.parent.postMessage as described in react-native-web-community/react-native-web-webview#37, but this creates another problem - now postMessage calls equally trigger events for all WebViews on the page, meaning all WebViews are going to get equal height.

The proper solution would probably be updating react-native-web-webview to implement window.ReactNativeWebView, but I couldn't find an easy way to do it, so I have instead made changes to this package (react-native-autoheight-webview).

The changes are as follows:
0. Unrelated to the main issue, but this package utilizes ViewPropTypes from react-native, however ViewPropTypes was removed from react-native-web (see necolas/react-native-web#1537). In order to fix this and make the package work on Web, change the following in autoHeightWebView/index.js:

-import {StyleSheet, Platform, ViewPropTypes} from 'react-native';
+import {StyleSheet, Platform} from 'react-native';
+import {ViewPropTypes} from 'deprecated-react-native-prop-types';

And install deprecated-react-native-prop-types in your project: npm install deprecated-react-native-prop-types --save
Right now deprecated-react-native-prop-types is a dependency of react-native (as of 0.68.2), but it may be removed later, so better install it separately.

  1. Now we need to make calls to window.parent when window.ReactNativeWebView is unavailable. In order to do that, change the following lines in autoHeightWebView/utils.js:
-    if (
-      !window.hasOwnProperty('ReactNativeWebView') || 
-      !window.ReactNativeWebView.hasOwnProperty('postMessage')
-    ) {
+    const poster = window.hasOwnProperty('ReactNativeWebView') ? window.ReactNativeWebView :
+          window.hasOwnProperty('parent') ? window.parent : window;
+    if (!poster.hasOwnProperty('postMessage')) {

and

-    tempZoomedin !== zoomedin && window.ReactNativeWebView.postMessage(JSON.stringify({ zoomedin: tempZoomedin, topic: ${topicString} }));
+    const poster = window.hasOwnProperty('ReactNativeWebView') ? window.ReactNativeWebView :
+      window.hasOwnProperty('parent') ? window.parent : window;
+      tempZoomedin !== zoomedin && poster.postMessage(JSON.stringify({ zoomedin: tempZoomedin, topic: ${topicString}, target: document.title }));
  1. Now we need something for message identification. In order to do that, I'm passing the post's ID to WebView's <title> tag and checking for it in the handleMessage function. For that, you need to make the following changes.
    2.1. In autoHeightWebView/utils.js:
-    window.ReactNativeWebView.postMessage(JSON.stringify({ width: Math.min(width, screen.width), height: height * usingScale, topic: ${topicString} }));
+    poster.postMessage(JSON.stringify({ width: Math.min(width, screen.width), height: height * usingScale, topic: ${topicString}, target: document.title }));

2.2. In autoHeightWebView/index.js:

    const {
+    source,
      style,
      onMessage,
      onSizeUpdated,
      scrollEnabledWithZoomedin,
      scrollEnabled,
    } = props;

and

          if (data.topic !== topic) {
            onMessage && onMessage(event);
            return;
          }
+        if (data.target) {
+          const title = source.html.match(/<title[^>]*>(.*)<\/title>/i)[1];
+          if (data.target != title) return;
+        }

2.3. In your WebView's HTML code, remember to pass the item's ID in the <title> tag, e.g.: <title>${props.object.id}</title>

  1. That's all, now you just need to create a package patch with npx patch-package react-native-autoheight-webview.

  2. As a bonus point - I've got a weird bug where my WebView's width would gradully reduce. It disappeared after I disabled all possible scrollbars, like this:

      <AutoHeightWebView
        scalesPageToFit={true}
        scrollEnabled={false}
        nestedScrollEnabled={false}
        showsHorizontalScrollIndicator={false}
        showsVerticalScrollIndicator={false}
        originWhitelist={["*"]}
        source={{
          baseUrl: "",
          html: html
        }}
      />

Also in your WebView's HTML code, add this style:

      <style>
      body {
        overflow: hidden;
      }
      </style>

After this, my WebViews finally got a working autoheight in Android, iOS and, most importantly, Web. If you don't want to follow the steps, you can just grab this patch file: react-native-autoheight-webview+1.6.1.txt. Rename it from ".txt" to ".patch" and put it in your project's "patches" directory.

I don't think this solution is elegant enough to warrant a Pull Request, but hopefully it will save someone time until react-native-web-webview is fixed (if ever).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant