OnMessage webview not called in physical device android
See original GitHub issueHi guys, please give me solution, my webview have javascript code so
-
iOS working
-
emulator working
-
physical device android not working
-
physical device android 8.1
-
RN version 57.0.1. I try upgrade 0.59.1 but not working
This is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { WebView, View, Dimensions, Platform, Image, Linking } from 'react-native';
import navigator from '../Lib/navigator';
import templates from './injectedTemplates';
import {
addImages,
resetImages,
} from '../Redux/actions';
import { showError } from './toasts';
import { COLORS } from '../Config/colorVars';
const screenHeight = Dimensions.get('window').height;
const wordsPerScreen = screenHeight * 120 / screenHeight;
const charsToScreens = str => str.split(' ').length / wordsPerScreen;
class WebViewAutoHeight extends Component {
constructor(props) {
super(props);
this.state = {
isRendering: true,
realContentHeight: charsToScreens(this.props.source.html) * screenHeight,
};
this.injectedJavaScript = this.injectedJavaScript.bind(this);
};
componentWillMount() {
if(this.props.fontSize == 'Large' && Platform.OS === 'android') {
this.setState({
realContentHeight: charsToScreens(this.props.source.html)*screenHeight*1.3
});
}
};
shouldComponentUpdate(nextProps, nextState) {
return this.props.source.html !== nextProps.source.html ||
this.state.realContentHeight !== nextState.realContentHeight;
};
onLoad() {
this.props.onLoad();
};
onMessage(event) {
const { action, params } = JSON.parse(event.nativeEvent.data);
switch (action) {
case 'heightCaculated': {
return this.setState({
realContentHeight: params.height,
isRendering: false,
});
};
case 'addImages': {
this.props.resetImages();
params.imgs.map(img => Image.prefetch(img));
return this.props.addImages(params.imgs);
};
case 'openGallery': {
return navigator.navigate('Gallery', {
index: params.index,
})
};
case 'openYoutube': {
return Linking.canOpenURL(params.href).then((supported) => {
if (!supported) {
showError(`Can't handle url: ${params.href}`)
return false
}
return Linking.openURL(params.href);
});
};
case 'openLink': {
const checkInteralPostLink = params.href.match(/https:\/\/(?:stg1.)?viblo.asia\/p\/.*-([a-zA-Z0-9]+)/);
if (checkInteralPostLink && checkInteralPostLink[1]) {
return navigator.navigate('SinglePost', {
post: { slug: checkInteralPostLink[1] },
}, checkInteralPostLink[1]);
}
const checkInteralUserLink = params.href.match(/https:\/\/(?:stg1.)?viblo.asia\/u\/([a-zA-Z0-9.]+)/);
if (checkInteralUserLink && checkInteralUserLink[1]) {
return navigator.navigate('UserProfile', {
user: checkInteralUserLink[1],
}, checkInteralUserLink[1]);
}
const checkInteralSeriesLink = params.href.match(/https:\/\/(?:stg1.)?viblo.asia\/s\/.*-([a-zA-Z0-9]+)/);
if (checkInteralSeriesLink && checkInteralSeriesLink[1]) {
return navigator.navigate('SingleSeries', {
series: checkInteralSeriesLink[1],
}, checkInteralSeriesLink[1]);
}
const checkInteralQuestionLink = params.href.match(/https:\/\/(?:stg1.)?viblo.asia\/q\/.*-([a-zA-Z0-9]+)/);
if (checkInteralQuestionLink && checkInteralQuestionLink[1]) {
return navigator.navigate('QuestionDetail', {
question: { hash_id: checkInteralQuestionLink[1] },
}, checkInteralQuestionLink[1]);
}
return navigator.navigate('Browser', {
url: params.href,
});
};
default:
return null;
};
};
hackBefore() {
return Platform.OS === 'ios' ?
`
(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; `
:
`
if (window.postMessage.length !== 1) {
window.postMessage = function(msg) {
setTimeout(function () {
window.postMessage(msg);
}, 1000);
}
}
`
}
hackAfter() {
return Platform.OS === 'ios' ? '})();' : ''
}
injectedJavaScript() {
return `
${this.hackBefore()}
NodeList.prototype.forEach = Array.prototype.forEach;
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest)
Element.prototype.closest = function(s) {
var el = this;
if (!document.documentElement.contains(el)) return null;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
function dispatchAction(action, params) {
window.postMessage(JSON.stringify({
action,
params,
}));
};
var contentDiv = document.querySelector('.md-contents');
dispatchAction('heightCaculated', {
height: contentDiv ? contentDiv.clientHeight : 0,
});
var imgs = [];
document.querySelectorAll('img:not(.emoji):not(.embedded-img):not(.embedded-btn)').forEach(function (img, index) {
var src = img.getAttribute('src');
imgs.push(src);
img.addEventListener('click', function (event) {
dispatchAction('openGallery', {
index: index,
});
});
});
dispatchAction('addImages', {
imgs: imgs,
});
document.querySelectorAll('a:not(.embedded-a)').forEach(function (a) {
a.addEventListener('click', function (event){
event.preventDefault();
dispatchAction('openLink', {
href: event.target.closest('a').getAttribute('href'),
});
return false;
});
});
document.querySelectorAll('a.embedded-a').forEach(function (a) {
a.addEventListener('click', function (event){
event.preventDefault();
dispatchAction('openYoutube', {
href: event.target.closest('a').getAttribute('href'),
});
return false;
});
});
document.querySelectorAll('img.embedded-btn').forEach(function (img) {
var a = img.previousElementSibling;
img.addEventListener('click', function (event){
dispatchAction('openYoutube', {
href: a.getAttribute('href'),
});
return false;
});
return false;
});
${this.hackAfter()}
`
};
render() {
const { source, fontSizeContent, fontSizeContentPre, highlightThemes, enableNightMode, ...otherProps } = this.props;
const { realContentHeight } = this.state;
const html = source.html;
return (
<View style={{ flex: 1 ,backgroundColor: enableNightMode ? COLORS.COLOR_NIGHT_MODE : COLORS.COLOR_UN_NIGHT_MODE}}>
<View
style={{
height: Platform.OS === 'ios' ? realContentHeight : realContentHeight < screenHeight ? screenHeight*70/100 : realContentHeight+screenHeight,
paddingHorizontal: 5,
backgroundColor: enableNightMode ? COLORS.COLOR_NIGHT_MODE : COLORS.COLOR_UN_NIGHT_MODE
}}
>
{
Platform.OS === 'android' ?
<WebView
{...otherProps}
javaScriptEnable={true}
domStorageEnabled={true}
mixedContentMode={'compatibility'}
source={{ baseUrl: '', html: templates[this.props.template]({html, fontSizeContent, fontSizeContentPre, highlightThemes, enableNightMode}) }}
onLoad={this.onLoad.bind(this)}
injectedJavaScript={this.injectedJavaScript()}
onMessage = {
(event) => {
let message = event.nativeEvent.data;
console.log(message);
console.log('message');
}
}
scrollEnabled={false}
style={{
height: realContentHeight,
backgroundColor: enableNightMode ? COLORS.COLOR_NIGHT_MODE : COLORS.COLOR_UN_NIGHT_MODE
}}
/>
: <WebView
{...otherProps}
javaScriptEnable={true}
domStorageEnabled={true}
mixedContentMode={'compatibility'}
source={{ html: templates[this.props.template]({html, fontSizeContent, fontSizeContentPre, highlightThemes, enableNightMode}) }}
onLoad={this.onLoad.bind(this)}
injectedJavaScript={this.injectedJavaScript()}
onMessage={this.onMessage.bind(this)}
scrollEnabled={false}
style={{
height: realContentHeight,
backgroundColor: enableNightMode ? COLORS.COLOR_NIGHT_MODE : COLORS.COLOR_UN_NIGHT_MODE
}}
/>
}
</View>
</View>
);
}
}
WebViewAutoHeight.propTypes = {
source: PropTypes.object.isRequired,
injectedJavaScript: PropTypes.string,
onLoad: PropTypes.func,
onMessage: PropTypes.func,
onNavigationStateChange: PropTypes.func,
template: PropTypes.string.isRequired,
style: WebView.propTypes.style
}
WebViewAutoHeight.defaultProps = {
onLoad: () => {
},
onMessage: () => {
},
onNavigationStateChange: () => {
},
}
const mapStateToProps = (state) => {
return {
fontSize: state.fontSize.fontSize,
highlightThemes: state.fontSize.highLight,
enableNightMode: state.fontSize.enable
}
}
export default connect(mapStateToProps, {
addImages,
resetImages,
})(WebViewAutoHeight)
and file template.js
import vibloStyle from './assets/viblo.css'
import darkStyle from './assets/dark.css'
import grayStyle from './assets/gray.css'
import {Dimensions} from 'react-native'
import {COLORS} from '../../Config/colorVars'
const screenWidth = Dimensions.get('window').width
const transferHtml = ({html, fontSizeContent, fontSizeContentPre, highlightThemes, enableNightMode}) => {
const highlight = highlightThemes === 'dark' ? darkStyle : grayStyle
return `
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=yes'>
<style>${highlight}</style>
<style>${vibloStyle}</style>
<style>
::-webkit-scrollbar {
display: none;
}
* {
line-height: normal;
font-size: ${fontSizeContent};
}
body {
text-align: left;
padding: 5;
border: none;
background-color: ${enableNightMode ? COLORS.COLOR_NIGHT_MODE : COLORS.COLOR_UN_NIGHT_MODE};
color: ${enableNightMode ? COLORS.COLOR_UN_NIGHT_MODE : COLORS.COLOR_NIGHT_MODE};
}
p {
color: ${enableNightMode ? COLORS.COLOR_UN_NIGHT_MODE : COLORS.COLOR_NIGHT_MODE} !important;
}
blockquote > p {
color: ${COLORS.COLOR_DESCRIPTION} !important;
}
p > code {
background: #EBEBEB !important;
color: black !important;
}
table {
max-width: 100px
}
td {
max-width: ${screenWidth*50/100};
font-size: ${screenWidth*3/100};
}
td > code {
font-size: ${screenWidth*3/100};
}
code {
padding: 0;
color: ${highlightThemes === 'dark' ? 'white' : 'black'} !important;
background: ${enableNightMode && COLORS.COLOR_ICON_NIGHT_MODE} !important;
}
pre > code {
background: ${highlightThemes === 'dark' ? 'black' : '#f1f2f3'} !important;
border-width: 1px;
border-style: solid;
border-color: white;
}
iframe {
width: 100%;
height: 250px;
}
ul {
padding-left: 20px;
}
ol {
padding-left: 0px;
}
li {
line-height: 30px;
padding: 10px;
}
li > code {
background: ${ enableNightMode ? COLORS.COLOR_ICON_NIGHT_MODE : '#EBEBEB'} !important;
color: black !important;
}
blockquote{
padding-top: 1px !important;
padding-bottom: 1px !important;
margin-bottom: 1px !important;
}
span {
font-size: ${fontSizeContentPre};
}
pre {
font-size: ${fontSizeContentPre};
}
.embedded-container {
position: relative;
}
.embedded-img {
width: 100%;
min-height: 180px;
opacity: 0.3;
}
.embedded-btn {
width: 50px;
height: 50px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div class='post-content-wrapper'>
<div class='md-contents post-content'>
${html}
</div>
</div>
<script>
var wideTables = Array.from(document.querySelectorAll('table')).filter(function(table) {
return table.rows[0].cells.length > 2;
});
wideTables.forEach(function(table) {
var hiddenThs = [];
table.querySelectorAll("th:nth-child(n+3)").forEach(function(th) {
hiddenThs.push(th.innerHTML);
th.remove();
});
table.querySelectorAll("tbody>tr").forEach(function(tr) {
var newTr = tr.cloneNode(true);
var expandedContent = Array.from(newTr.querySelectorAll("td:nth-child(n+3)")).map(function(td, index) {
var newTd = '<li><b>' + hiddenThs[index] + '</b>:' + td.innerHTML + '</li>';
td.remove();
return newTd;
}).join('');
var toggleIcon = document.createElement('span');
toggleIcon.style.color = '#5488c7';
toggleIcon.style.margin = '0 10px';
var textNode = document.createTextNode('\u25BC');
toggleIcon.appendChild(textNode);
newTr.children[0].insertBefore(toggleIcon, newTr.children[0].firstChild);
newTr.addEventListener('click', function() {
if (newTr.nextSibling.nodeType === 3) {
toggleIcon.innerHTML = '\u25B2';
newTr.insertAdjacentHTML('afterEnd', '<tr><td colspan="2">' + '<ul class="row-more-detail">' + expandedContent + '</ul>' + '</td></tr>');
} else {
toggleIcon.innerHTML = '\u25BC';
newTr.nextSibling.remove();
}
var contentDiv = document.querySelector('.md-contents');
if (contentDiv) {
window.postMessage(JSON.stringify({
action: 'heightCaculated',
params: {
height: contentDiv.clientHeight
},
}));
};
}, false);
tr.parentNode.replaceChild(newTr, tr);
});
});
</script>
</body>
</html>`
}
export default transferHtml
Please help me, Thanks!
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (1 by maintainers)
Top Results From Across the Web
OnMessage webview not called in physical device android #463
Hi guys, please give me solution, my webview have javascript code so iOS working emulator working physical device android not working ...
Read more >onMessage android Webview React Native not working in ...
My webview contain (embed, code, ...) so because i used onMessage and injectedJavascript, i'm try console event in onMessage in ios and ...
Read more >HTML : React Native WebView onMessage doesn't do anything
HTML : React Native WebView onMessage doesn't do anything [ Gift : Animated ... provided in this video is as it is with...
Read more >App security best practices - Android Developers
If your app uses Google Play services, make sure that it's updated on the device where your app is installed. Perform the check...
Read more >Using the TomTom Maps Web SDK in a React Native Web ...
React Native WebView helps your JavaScript application's maps look great across ... look across iOS and Android devices — without coding twice.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Since
WebView
was remove from React Native @https://github.com/facebook/react-native/commit/6345fcf12bd05f51ec2c5340a10add52780ac681. This issue should be migrate to https://github.com/react-native-community/react-native-webview and close.My solution: I’m assign a references in Webview and setTimeout 3s call this references, but sometime working error!