title: Refactoring AutoHeightWebView library to get hyperlinks to open up in separate browser
body: <p>I have a React Native application that I upgraded. Back when it was legacy, if you went to a news article and the article had hyperlinks and you clicked on the hyperlinks it would redirect you to your phones browser and open the link there, but it no longer does that because we had to upgrade the <code>react-native-autoheight-webview</code> library, so the patch that was done for the 0.6.1 version is now gone. That patch is what allowed hyperlinks to open in a separate browser.</p>
  
  <p>I have been trying to repeat the process so we can get the same behavior. So I added this code to <code>node_modules/react-native-autoheight-webview/AutoHeightWebView/index.js</code> file:</p>
  
  <pre><code>const _onLoadStart = event =&gt; {
      if (event.nativeEvent.url.startsWith("http")) {
          this.stopLoading();
          Linking.openURL(event.nativeEvent.url).catch(err =&gt; console.log('An error occurred', err));
      } else {
          const {onLoadStart} = this.props;
          onLoadStart &amp;&amp; onLoadStart(event);
      }
    }
  
      const { currentSource, script } = reduceData(props);
  
      const { width, height } = size;
      useEffect(
        () =&gt;
          onSizeUpdated &amp;&amp;
          onSizeUpdated({
            height,
            width
          }),
        [width, height, onSizeUpdated]
      );
  
  
  
      return (
        &lt;WebView
          {...props}
          ref={webView}
          onMessage={handleMessage}
          onLoadStart={_onLoadStart}
          style={[
            styles.webView,
            {
              width,
              height
            },
            style
          ]}
          injectedJavaScript={script}
          source={currentSource}
        /&gt;
      );
    }),
    (prevProps, nextProps) =&gt; !shouldUpdate({ prevProps, nextProps })
  );
  </code></pre>
  
  <p>but that did nothing.</p>
  
  <p>I also tried this in the same file:</p>
  
  <pre><code>const uri = `${media}/1.0/articles`;
  
      return (
        &lt;WebView
          {...props}
          ref={webView}
          onMessage={handleMessage}
          source={{uri}}
          onNavigationStateChange={(event) =&gt; {
            if (event.url !== uri) {
              this.webview.stopLoading();
              Linking.openURL(event.url);
            }
          }}
          style={[
            styles.webView,
            {
              width,
              height
            },
            style
          ]}
          injectedJavaScript={script}
          source={currentSource}
        /&gt;
      );
  </code></pre>
  
  <p>And nothing.</p>
  
  <p>I cannot go back to <code>react-native-autoheight-webview@0.6.1</code> and do another patch package because that version is incompatible with React Native 60s versioning, namely we no longer use <code>index.ios.js/index.android.js</code> but instead <code>index.js</code>. </p>
  
  <p>The earliest package of <code>react-native-autoheight-webview</code> would be 1.0.0 and its a moot point by that version because the <code>WebView</code> and <code>Linking</code> module are no longer in the <code>react-native</code> library, but inside of <code>react-native-webview</code> library and it doesn't look like it supports the same properties to get a user to open a hyperlink in a separate browser as opposed to within the webview of the application. At least I have been unsuccessful in trying.</p>
  
  <p>I also tried a complimentary package <code>react-native-webview-bridge</code> to come to the rescue but that package began crashing my application on both the iOS and Android side, so that was not a viable solution. Here are a couple of examples of how this approach failed:</p>
  
  <pre><code>Undefined symbols for architecture arm64:
    "_RCTJSNavigationScheme", referenced from:
        -[RCTWebViewBridgeManager constantsToExport] in libReact-Native-Webview-Bridge.a(RCTWebViewBridgeManager.o)
        -[RCTWebViewBridge webView:shouldStartLoadWithRequest:navigationType:] in libReact-Native-Webview-Bridge.a(RCTWebViewBridge.o)
  ld: symbol(s) not found for architecture arm64
  clang: error: linker command failed with exit code 1 (use -v to see invocation)
  </code></pre>
  
  <p>on the iOS side, on the Android side I got this error:</p>
  
  <pre><code>2019-10-17 13:01:14.292 15725-15839/com.nfibengage.dv E/AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
      Process: com.nfibengage.dv, PID: 15725
      java.lang.NoClassDefFoundError: Failed resolution of: Lcom/facebook/react/views/webv
  </code></pre>
  
  <p>I guess at the end of the day, how do I successfully instruct my app to open an external link in an outside browser via communicating with React Native from the DOM?</p>
  
  <p>I tried this configuration inside of `node_modules/react-native-autoheight-webview/AutoHeightWebView/index.js:</p>
  
  <pre><code>jsCode = () =&gt; {
     const attachEvent = function(elem, event, callback) {
       event = event.replace(/^on/g, '');
       if ('addEventListener' in window) {
         elem.addEventListener(event, callback, false);
       } else if ('attachEvent' in window) {
         elem.attachEvent('on' + event, callback);
       } else {
         const registered = elem['on' + event];
         elem['on' + event] = registered ? function(e) {
           registered(e);
           callback(e);
         } : callback;
       }
  
       return elem;
     }
  
     const all_links = document.querySelectorAll('a[href]');
  
     if (all_links) {
       for (var i in all_links) {
         if (all_links.hasOwnProperty(i)) {
           attachEvent(all_links[i], 'onclick', function(e) {
             if (!new RegExp('^https?:\/\/' + location.host, 'gi').test(this.href)) {
               // handle external URL
               e.preventDefault();
  
               window.postMessage(JSON.stringify({
                 external_url_open: this.href
               }));
             }
           });
         }
       }
     }
   }
  
  
  
   render() {
     const { height, width } = this.state;
     const { style, originWhitelist } = this.props;
     const { source, script } = this.getUpdatedState(this.props, getBaseScript);
     return (
       &lt;WebView
         {...this.props}
         originWhitelist={originWhitelist || ['*']}
         ref={this.webView}
         onMessage={this.onMessage}
         style={[
           styles.webView,
           {
             width,
             height
           },
           style
         ]}
         injectedJavaScript={this.jsCode}
         source={source}
       /&gt;
     );
   }
  }
  </code></pre>
  
  <p>using this documentation as a guide:
  <a href="https://medium.com/@elhardoum/opening-external-links-in-browser-in-react-native-webview-18fe6a66312a" rel="nofollow noreferrer">https://medium.com/@elhardoum/opening-external-links-in-browser-in-react-native-webview-18fe6a66312a</a></p>
  
  <p>It has done nothing for me.</p>
  
  <p>Next I tried adding the <code>onNavigationStateChange</code> property to my <code>ActionAlertFeedCard</code>:</p>
  
  <pre><code>import React from "react";
  import {
    Text,
    StyleSheet,
    View,
    TouchableOpacity,
    Platform
  } from "react-native";
  import { WebView } from "react-native-webview";
  import { TextButton } from "react-native-material-buttons";
  import PropTypes from "prop-types";
  import format from "date-fns/format";
  import { Card, Divider } from "common-components";
  import { v2Colors, feedContentStyles, v2ButtonStyles } from "theme";
  import { moderateScale } from "react-native-size-matters";
  
  //prettier-ignore
  const getHtml = content =&gt; `&lt;body style="font-family: -apple-system, Roboto, sans-serif; font-size: ${moderateScale(32, 0.2)}px;"&gt;${content}&lt;/body&gt;`;
  
  const ActionAlertFeedCard = ({
    completed,
    content,
    datePosted,
    mainActionButtonPress,
    secondaryActionButtonPress,
    style,
    title
  }) =&gt; (
    &lt;Card style={style}&gt;
      &lt;View style={feedContentStyles.header}&gt;
        &lt;Text style={feedContentStyles.title}&gt;{"ACTION ALERT"}&lt;/Text&gt;
        &lt;Text style={feedContentStyles.postDate}&gt;
          {`${completed ? "Completed" : "Posted"} ${format(
            datePosted,
            "MMM D, YYYY"
          )}`}
        &lt;/Text&gt;
      &lt;/View&gt;
      &lt;Divider /&gt;
      &lt;View style={feedContentStyles.content}&gt;
        &lt;Text style={feedContentStyles.contentTitle}&gt;{title}&lt;/Text&gt;
        &lt;WebView
          useWebKit={true}
          scrollEnabled={false}
          style={styles.webview}
          source={{
            html: getHtml(content)
          }}
          onNavigationStateChange={event =&gt; {
            console.log("url of webpage" + event.url);
          }}
          // scalesPageToFit={Platform.OS !== "ios"}
        /&gt;
  </code></pre>
  
  <p>The news articles never completed loading up.</p>