我有一个适用于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>
)