Reputation: 387
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!
Upvotes: 0
Views: 1161
Reputation: 2053
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>
)
Upvotes: 0
Reputation: 1078
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
Upvotes: 1