React native webview component can not open links on Android, but on IOS it works fine, without any troubles. Nothing has happening on Android, after the pressing, no any errors. At the same time i tried to open links with react native hyperlink, and it works fine. Can you tell me please how can i solve it?
const IS_IOS = Platform.OS === 'ios';
const script = `
;(function() {
var wrapper = document.createElement("div");
wrapper.id = "height-wrapper";
while (document.body.firstChild) {
wrapper.appendChild(document.body.firstChild);
}
document.body.appendChild(wrapper);
var i = 0;
function click(e) {
e.preventDefault();
window.postMessage(click, '*');
};
function updateHeight() {
document.title = wrapper.scrollHeight;
window.location.hash = ++i;
}
function linkProcessed() {
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].onclick = function (e) {
e.preventDefault();
window.ReactNativeWebView.postMessage(e.currentTarget.getAttribute("href"), '*');
}
}
var links = document.getElementsByTagName('img');
for (var i = 0; i < links.length; i++) {
links[i].onclick = function (e) {
e.preventDefault();
window.ReactNativeWebView.postMessage(e.currentTarget.getAttribute("src"), '*');
}
}
}
updateHeight();
setTimeout(linkProcessed, 1000);
window.addEventListener("load", function() {
updateHeight();
setTimeout(updateHeight, 1000);
});
window.addEventListener("resize", updateHeight);
}());
`;
const postMessage = `(function() {
var originalPostMessage = window.postMessage;
var patchedPostMessage = function(message, targetOrigin, transfer) {
originalPostMessage(message, targetOrigin, transfer);
};
patchedPostMessage.toString = function() {
return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
};
window.postMessage = patchedPostMessage;
})();`;
const style = `
<style>
body, html, #height-wrapper {
margin: 0;
padding: 0;
}
#height-wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
}
</style>
<script>
${script}
</script>
`;
const textStyleToCss = (textStyle: StyleProp<TextStyle>, styles?: StyleProp<ViewStyle>): string => {
if (!textStyle) {
return '';
}
const {
fontSize,
fontFamily,
fontUrl,
lineHeight,
letterSpacing,
color,
} = StyleSheet.flatten(textStyle) as any;
const {
backgroundColor,
} = StyleSheet.flatten(styles) as any;
const css = IS_IOS ?
`<style type="text/css">@font-face {font-family: MyFont; font-style: normal;
font-weight: 400; src: local('${fontFamily}'), url('${fontUrl}');}
body,* {
font-family: MyFont; font-size: ${fontSize}pt;text-align: left; line-height: ${lineHeight}pt; letter-spacing: ${letterSpacing}pt; color: ${color};
background-color: ${backgroundColor};
}
img{height: auto;max-width: 100%;}
iframe {height: auto;max-width: 100%;}
div{height: auto;max-width: 100%;}
</style>` :
`<style type="text/css">@font-face {font-family: MyFont; font-style: normal;
font-weight: 400; src: url("${fontUrl}");}
body,* {
font-family: MyFont; font-size: ${fontSize}px;text-align: left; line-height: ${lineHeight}px; letter-spacing: ${letterSpacing}px; color: ${color};
background-color: ${backgroundColor};
}
img{height: auto;max-width: 100%;}
iframe {height: auto;max-width: 100%;}
div{height: auto;max-width: 100%;}
</style>`;
return css;
};
const markdownLinksMap = (text: string) => {
const markdownLinkReg = /\[([^\[\]]+)\]\(([^)]+)\)/img;
text = text.replace(markdownLinkReg, (substring, ...args) => {
const title = args[0];
const url = args[1];
const linkKey = `<a href="${url}">${title}</a>`;
return linkKey;
});
return text;
};
const codeInject = (args: { html: string, textStyle?: StyleProp<TextStyle>, style?: StyleProp<ViewStyle> }): string => {
const textWithoutMarkdown = markdownLinksMap(args.html);
return (`
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
${textStyleToCss(args.textStyle, args.style)}
</head>
<body>${'<div style="color: ' + args.textStyle!.color + '">' + textWithoutMarkdown + '</div>'}${style}</body>
`)
};
interface TextStyleProp extends TextStyle {
fontSize: number;
fontFamily: string;
lineHeight: number;
letterSpacing: number;
color: string;
fontUrl: string;
}
interface Props {
html: string;
navigateToWebview?: (url: string) => void;
style?: StyleProp<ViewStyle>;
textStyle?: StyleProp<TextStyleProp>;
}
interface State {
correctHtml: string;
height: number;
}
export class AutoHeightWebView extends React.Component<Props, State> {
public static getDerivedStateFromProps(props: Props, state: State) {
if (props.html) {
const correctHtml = codeInject(props);
return { correctHtml };
}
return null;
}
private webview: any;
constructor(props: Props) {
super(props);
this.state = {
correctHtml: codeInject(props),
height: 120,
};
}
public componentWillUnmount(): void {
if (this.webview) {
this.webview.stopLoading();
this.webview = null;
}
}
public render() {
if (!(this.props.html && this.props.html.length > 0)) {
return (<View />);
} else {
return (
<View style={[SS.container, this.props.style]}>
<WebView
ref={this.setWebView}
automaticallyAdjustContentInsets={true}
source={{ html: this.state.correctHtml, baseUrl: '' }}
onMessage={this.onMessage}
javaScriptEnabled={true}
injectedJavaScript={`${postMessage};document.body.scrollHeight;`}
style={{ height: this.state.height }}
onNavigationStateChange={this.onNavigationChange}
domStorageEnabled={true}
scalesPageToFit={Platform.select({ios: undefined, android: true})}
startInLoadingState={true}
scrollEnabled={true}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
bounces={false}
originWhitelist={['*']}
/>
</View>
);
}
}
private onNavigationChange = (event: NavState): void => {
if (event.title) {
const htmlHeight = Number(event.title); //convert to number
if (htmlHeight && this.state.height !== htmlHeight) {
this.setState({ height: htmlHeight });
}
}
}
private onMessage = (event: NativeSyntheticEvent<WebViewMessageEventData>): void => {
const url = event.nativeEvent.data;
if (this.props.navigateToWebview) {
this.props.navigateToWebview(url);
} else {
Linking.openURL(url);
}
}
private setWebView = (webview: any): void => {
this.webview = webview;
};
}
const SS = EStyleSheet.create({
container: { flex: 1, overflow: 'hidden' },
});