简体   繁体   中英

React Native WebView JavaScript issue on build

I've got a React Native application for Android that has live chat support (using Intercom). To access Intercom I'm using WebView with injectedJavaScript to show the UI. It works fine on my dev build, but when I do a release build it complains it cannot find window.Intercom (I get the same relative issue if I remove the window. )

Here's the code I'm trying to run

IntercomContainer.js

// =============================================================================
// Components >> IntercomContainer
// =============================================================================
// @flow

// Import
// =============================================================================

import * as React from 'react';
import { View, WebView } from 'react-native';
import Spinner from 'react-native-loading-spinner-overlay';

import styles from './styles';

// Content
// =============================================================================

type State = {
    isLoading: boolean,
};

type Props = {
    appId: string,
}

// Render
// =============================================================================

export default class IntercomContainer extends React.Component<Props, State> {

    props: Props = {
        appId: '',
    };

    state: State = {
        isLoading: true,
    }

    setState: Function;

    injectedJS = (appId: string) => {
        return `
            try {

                window.Intercom('boot', {
                    app_id: '${appId}',
                }); 

                window.Intercom('show');
                window.Intercom('onShow', function() { 
                    document.getElementById('message').innerHTML = '';
                    setTimeout(() => {
                        document.getElementById('message').innerHTML = 'Click on the chat button in the bottom-right to open chat...';
                    }, 1000)
                });

            } catch(e) {
                alert('Intercom failed to load: ' + e.message);
            }
        `;
    }

    onLoadEnd = () => {
        this.setState({
            isLoading: false,
        });
    }

    render(){
        const { appId } = this.props;
        const { isLoading } = this.state;

        return (
            <View style={styles.container}>
                <Spinner visible={isLoading} />
                <WebView
                    injectedJavaScript={this.injectedJS(appId)}
                    source={require('./IntercomWebView.html')}
                    onLoadEnd={this.onLoadEnd}
                    javaScriptEnabled={true}
                    style={styles.webView}
                />
            </View>
        );
    }
}

IntercomWebView.html

<!DOCTYPE html>
<head>
    <script>
        // intercom JS library
        var APP_ID = '';
        (function(){
            debugger;
            console.log("Executing function main...");
            var w=window;
            var ic=w.Intercom;
            if (typeof ic === "function") {
                ic('reattach_activator');
                ic('update',intercomSettings);
            } else {
                var d=document;
                var i= function() {
                    i.c(arguments)
                };
                i.q=[];
                i.c=function(args){
                    i.q.push(args)
                };
                w.Intercom=i;

                function l(){
                    debugger;
                    console.log("Executing function l...");
                    var s=d.createElement('script');
                    s.type='text/javascript';
                    s.async=true;
                    s.src='https://widget.intercom.io/widget/' + APP_ID;
                    var x=d.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s,x);
                }

                if(w.attachEvent){
                    w.attachEvent('onload',l);
                }else{
                    w.addEventListener('load',l,false);
                }
            }
        })();
    </script>
    <style>
        main {
            align-items: center;
            background-color: #fefefe;
            color: #999;
            display: flex;
            font-family: sans-serif;
            height: 80vh;
            justify-content: center;
            text-align: center;
        }
    </style>
</head>
<body>
    <main id="message">
        loading...
    </main>
</body>
</html>

Thanks!

Most likely the root cause of your issue is the same as postMessage bug. Your code which uses Intercom object is being loaded before javascript code which initilizes this object. As a workaround you can call this code in setTimeout with some magic value, or implement more "neat" solution where you'll defer actual calls of Intercom object until it is initialized

This seems to be an issue as referred to above with the delay, but also a cookies problem.

I managed to get around this with the following, similar to the original question;

const injectedJavaScript = `
  var APP_ID = "YOUR_APP_ID";
  // Wait for a "time" before trying to execute
  setTimeout(function() {
    try {
      window.Intercom('boot', {
        app_id: APP_ID,
        email: 'an_email_@an_address.com',
        user_id: 'unique_id'
      });
      // i want to show by default, when ready
      window.Intercom('show');
      // then i am doing some stuff to show the "instruction" to reopen by the icon if they close
      var instruction = document.getElementById("instruction");
      window.Intercom('onHide', function() {
        instruction.classList.add("show");
      })
    } catch(e) {
      alert('Intercom failed to load: ' + e.message);
    }
  }, 500)
`

My WebView looks like this;

return (
  <View flex={1}>
    <WebView
      javaScriptEnabled
      scrollEnabled={false}
      bounces={false}
      originWhitelist={['*']}
      injectedJavaScript={injectedJavaScript}
      source={{
        html: `
          <head>
            <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0">
            <style>
              p#instruction {
                opacity: 0;
                font-family: 'Rubik', sans-serif;
                text-align: center;
                font-size: 14px;
                position: absolute;
                top: 50%;
                left: 0;
                margin-top: -8px;
                width: 100%;
                -webkit-transition: opacity 0.5s linear;
                -moz-transition: opacity 0.5s linear;
                -o-transition: opacity 0.5s linear;
                -ms-transition: opacity 0.5s linear;
                transition: opacity 0.5s linear;
              }
              p#instruction.show {
                opacity: 1;
              }

            </style>
          </head>
          <body>
            <p id="instruction">Click the icon to open chat</p>
            <script>
              var APP_ID = "YOUR_APP_ID";

              (function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',w.intercomSettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Intercom=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/' + APP_ID;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s,x);};if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();
            </script>
          </body>
        `,
        baseUrl: 'https://a-base-url.co.uk', // This part is important! This solved the cookie issue for me
      }}
      useWebKit
      onLoad={() => console.warn('do something on load')}
    />
  </View>
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM