React Native WebView JavaScript issue on build



我有一个适用于Android的React Native应用程序,它支持实时聊天(使用对讲机)。要访问对讲机,我正在使用带有injectedJavaScript WebView来显示UI。它在我的开发版本上运行良好,但是当我进行发布版本时,它抱怨找不到window.Intercom(如果我删除window.,我会遇到同样的相对问题)

这是我尝试运行的代码

对讲机容器.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>
        );
    }
}

对讲机网络视图.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>

谢谢!

问题的根本原因很可能与postMessage bug相同。使用Intercom对象的代码在启动此对象的 javascript 代码之前加载。作为一种解决方法,您可以使用一些魔术值在setTimeout调用此代码,或者实现更"简洁"的解决方案,您将推迟Intercom对象的实际调用,直到它被初始化

这似乎是上面提到的延迟问题,但也是一个cookies问题。

我设法通过以下内容解决了这个问题,类似于原始问题;

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)
`

我的网络视图如下所示;

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>
)

最新更新