简体   繁体   English

在构建时反应本机WebView JavaScript问题

[英]React Native WebView JavaScript issue on build

I've got a React Native application for Android that has live chat support (using Intercom). 我有一个具有实时聊天支持(使用内部通信)的Android React Native应用程序。 To access Intercom I'm using WebView with injectedJavaScript to show the UI. 要访问对讲我使用WebViewinjectedJavaScript以显示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. ) 它在我的开发版本上运行良好,但是当我进行发布版本时,它抱怨找不到window.Intercom (如果删除window.我会遇到相同的相对问题window.

Here's the code I'm trying to run 这是我要运行的代码

IntercomContainer.js 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 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. 您问题的根本原因很可能与postMessage错误相同。 Your code which uses Intercom object is being loaded before javascript code which initilizes this object. 使用Intercom对象的代码将在初始化该对象的JavaScript代码之前加载。 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 作为一种解决方法,您可以使用一些神奇的值在setTimeout调用此代码,或者实施更多的“整洁”的解决方案 ,在此解决方案中 ,您将对Intercom对象的实际调用推迟到初始化之前

This seems to be an issue as referred to above with the delay, but also a cookies problem. 这似乎是上面提到的延迟问题,但也是cookies问题。

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; 我的WebView看起来像这样;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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