React-native Display of AutoHeightWebView causes crash in Android 10 and Android 11 - react-native

I seldom ask a question but want to see whether someone has a similar experience.
In coding a react-native app, I've included the component AutoHeightWebView on a page (together with other components, such as text and images.)
A strange behaviour occurs is that when the app is installed in physical devices:
For devices of Android 9 and below: normal
For devices of Android 10 and 11: app will crash when this page is displayed (say navigated from another page)
The following is extract of the code
import React, {Component} from 'react';
import AutoHeightWebView from 'react-native-autoheight-webview'
import { Dimensions } from 'react-native'
// other imports
export default class NdetailScreen extends Component {
render(){
return (
<View style={{ flex: 1, alignItems: 'center' }}>
<ScrollView style={{flex:1}}>
<Image
resizeMode={'contain'}
style={{ width: '100%', height: 200 }}
source={{uri: this.state.homepic}}
/>
<AutoHeightWebView
style={{ width: Dimensions.get('window').width , marginTop: 0 }}
source={{ uri: 'https://xxxxxx.com/nshow.php?serial=' + this.props.route.params.unitserial + '&lang=' + this.props.route.params.lang }}
scalesPageToFit={false}
viewportContent={'width=device-width, user-scalable=no'}
/>
<View style={{height:80}}><Text> ... other text </Text></View>
</ScrollView>
</View>
)
}
}
The strange thing is, if I remove the following block, everything works fine (in the Android 10 and 11 smartphones):
<AutoHeightWebView
style={{ width: Dimensions.get('window').width , marginTop: 0 }}
source={{ uri: 'https://xxxxxx.com/nshow.php?serial=' + this.props.route.params.unitserial + '&lang=' + this.props.route.params.lang }}
scalesPageToFit={false}
viewportContent={'width=device-width, user-scalable=no'}
/>
Any advice ?

I believe it is a bug of AutoHeightWebView (because I have already used the most up-dated version of AutoHeightWebView and my expo / npm versions are all up-to-date.
After repeatedly observing the "crash" behaviour, I have found that if I've removed the AutoHeightWebView part, there will NOT be any crash. So it can be run without problem in an Android 10/11 devices. After that if I re-added the AutoHeightWebView part -- there will be no crash ! (you know it can be done by real-time updating of code when the device is connected to the expo development platform)
So if the AutoHeightWebView part is already there while I navigate to the screen, it will crash in the Android 10/11 devices, but if it is "added" LATER, it will be fine.
Hence, I have used a trick to fix the problem.
change the code so that the AutoHeightWebView part will NOT be rendered when the page is first loaded
in the componentDidMount() part, add a setTimeout function (say 0.5 second) to change a control state so that the AutoHeightWebView will be rendered again after 0.5 seconds when the page is loaded
The following is the code
constructor() {
super();
this.state={xxtime4:0}
}
componentDidMount() {
setTimeout(() => {
this.setState({xxtime4:'10'});
}, 500);
}
kenlist3() {
if (this.state.xxtime4==0) {
return null
} else {
return (
<AutoHeightWebView
style={{ width: Dimensions.get('window').width , marginTop: 0 }}
source={{ uri: 'https://www.xxxxx.com/displaytext.php' }}
scalesPageToFit={false}
viewportContent={'width=device-width, user-scalable=no'}
/>
)
} }
In this way, if I use {this.kenlist3()}, it will be able to display the AutoView in all the physical devices. (including Android 10/11).
I just hope that in future this bug will be fixed by the developer so that I do not need to use such a "trick". But at least it is fine for the time being.
Hope that the above can also help someone.

Related

KeyboardView not working on android (React-Native)

I have a screen with header and content, and in the content section I have a search and I want when I open the keyboard to raise all the view. I tried keyboardAvoidingView but it's not working for me. What I am doing wrong here ?
return (
<View style={styles.content}>
<View style={styles.header}>
...
</View>
<KeyboardAvoidingView
keyboardVerticalOffset={hp(30)}
style={{flex: 1}}
behavior="padding">
...
</KeyboardAvoidingView>
</View>
);
and for the styling:
header: {
height: hp(30),
width: wp(100),
},
container: {
flexGrow: 1,
backgroundColor: Colors.white,
// borderTopLeftRadius: wp(7),
// borderTopRightRadius: wp(7),
},
and here is how it looks
On Android, when you style the root View to flex:1, the application height will automatically reduce by the keyboard height when keyboard is shown.
And for using of KeyboardAvoidingView, this component should be put to an as high as possible level. Formally, you shouldn't place any sized component outside it to prevent some display problems. And to adapt this component, please make sure to check the compatibility both iOS and Android. It has different behavior on the two systems.
You could try setting the behavior to be platform specific like so:
<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : undefined}>
// ...
</KeyboardAvoidingView>
It behaves slightly different on iOS and Android and this fixed my issues.
I've also seen react-native-keyboard-aware-scroll-view recommended on many posts regarding the same topic. It might be a more reliable thing to use according to other users but I haven't tried it.

Why Flatlist isn't rendering properly when android build apk orientation changes?

I'm using expo to build a pantry service app and I'm fetching a list of items from a node pantry server then render them on the app using Flatlist.
Everything works as expected except for one thing and that is the flatlist rendering when Orientation changes.
When testing with the expo app it works flawlessly even when the orientation changes.
Problem: When building android apk and testing it on device flatlist no longer renders as expected and for instance:
-> When starting the app in portrait mode you can scroll all the way to the bottom but when you rotate the device I'm unable to scroll all the way to the bottom or it seems I can but the rest of the items seem to be clipped beyond the device display borders.
-> Conversely when I start the app in landscape mode I'm able to scroll to the bottom with no issue but when I change the orientation to portrait the flatlist renders only half way through the screen, I'm still able to scroll to the end of it.
I've tried passing to extraData as well add flexgrow to contentContainerStyle,I've also tried using ScrollView instead of View but there are no noticeable improvements.
const [refreshing,setRefreshing] = useState(false)
ScreenOrientation.addOrientationChangeListener(
evt => {
setCurrOrientation(evt.orientationInfo.orientation)
setRefreshing(!refreshing)
}
)
ScreenOrientation.getOrientationAsync().then(result => setCurrOrientation(result.orientation))
keyExtractor = (item, index) => index.toString()
renderItem = ({ item,index }) => (
<ListItem
key={index}
leftAvatar={{ source: { uri: BASE_URL + ':' + PORT + '/uploads/' + item.rowid + '/image.png' } }}
title={<Text style={{ fontFamily: 'fake-receipt' }}>{item.item_name}</Text>}
subtitle={<Text style={{ fontFamily: 'fake-receipt', color: 'grey', fontSize: 10 }}>{item.item_type}</Text>}
containerStyle={{ borderBottomColor: '#F0F0F0', borderBottomWidth: 1, borderBottomStartRadius: 10, borderTopStartRadius: 10 }}
onPress={() => {
setSelectedItemIndex(index);
setSelectedItemRowID(item.rowid);
setSelectedItemSugarCondition(item.sugar === 'yes' ? 'yes' : 'no');
setOverlayVisible(true);
}}
rightIcon={<IconFA name={'plus'}
size={20}
color='#26a69a'
/>}
/>
)
<View>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
extraData={refreshing}
keyExtractor={this.keyExtractor}
data={itemsList}
renderItem={this.renderItem}
/>
</View>
Its puzzling me how it works fine in the expo app but not the expo android build, any ideas how I can fix this or if there is a better alternative?
I'm using expo 3.0.10 and device is running Android 9 Pie
I have figured it out, I used Dimensions with another view and placed flatlist inside it, this rendered the flatlist properly after orientation.
<View style={{ backgroundColor: '#f1f1f1', flex: 1 }}>
<View style={{height:Dimensions.get('window').height - 80}}>
<FlatList
extraData={refreshing}
keyExtractor={this.keyExtractor}
data={itemsList}
renderItem={this.renderItem}
/>
</View>
</View>

Showing high res images makes my app crash in my react-native app, How can I solve this?

I need to show about 20 high res images in my view with scroll, so when I run my app during the scroll my app will crash in my iphone 6 plus. I checked xcode and find this error message:
[process_info] Exiting because our workspace host has disconnected.
XPC connection interrupted
I had a flat list with lots of imageSlides in it, which each one of them is a 'JourneySlide' component.
here is my code :
export class JourneySlide extends Component {
constructor(props){
super(props);
this.state = {
refreshCount : 0,
}
}
constructViews = () => {
let slideMissions = [];
this.props.levels.forEach((item , index)=> {
slideMissions.push(
<JourneyMission
maxLvlNumber={this.props.levels[0].level_number}
seasonID={this.props.season_id}
is_locked={item.is_locked}
is_completed={item.is_completed}
prize_value={item.prize_value}
prize_type={item.prize_type}
level_number={item.level_number}
message=""
level_id={item.level_id}
onPress={this.props.onPress}
itemIndex={index}
asset_height={this.props.asset_height}
asset_width={this.props.asset_width}
pos_Y={item.pos_Y}
pos_x={item.pos_x}
/>
)
})
return slideMissions;
}
render() {
console.log('Journey Slide render again')
let sizeH = normalize(42);
let {
asset_height,
asset_width,
asset_name,
title,
sub_title,
} = this.props;
let slideHeight = checkHeight(asset_width,asset_height)
return (
<View style={[{height: slideHeight, width : widthx}]}>
{/* {this.constructViews()} */}
<FlatList
data={this.props.levels}
keyExtractor={(item) => item.level_id }
renderItem={({item, index}) =>
<JourneyMission
maxLvlNumber={this.props.levels[0].level_number}
seasonID={this.props.season_id}
is_locked={item.is_locked}
is_completed={item.is_completed}
prize_value={item.prize_value}
prize_type={item.prize_type}
level_number={item.level_number}
message=""
level_id={item.level_id}
onPress={this.props.onPress}
itemIndex={index}
asset_height={this.props.asset_height}
asset_width={this.props.asset_width}
pos_Y={item.pos_Y}
pos_x={item.pos_x}
/>}
showsVerticalScrollIndicator={false}
style={{zIndex:2}}
getItemLayout={(data, index) => (
{length: sizeH, offset: sizeH * index, index}
)}
/>
<Image
style={{
position: 'absolute',
zIndex: 1,
width: widthx,
height: slideHeight
}}
// resizeMode="stretch"
resizeMethod="resize"
source={journey[asset_name]}
/>
</View>
);
}
}
this is where I add each images to my view witch they usually have 2048*2732 and above res
<Image
style={{
position: 'absolute',
zIndex: 1,
width: widthx,
height: slideHeight
}}
// resizeMode="stretch"
resizeMethod="resize"
source={journey[asset_name]}
/>
So my problem is the crash issue during the scrolling, I also checked memory use during scroll, it's about 200 mb and 20% cpu usage during scroll.
I checked this app on newer iphone and it works fine but I need to handle this issue on iphone 6 and 5s
please help me with your advices.
Two suspicious:
(1) I would take a look at (flatlist-performance-tips) for general tips, but in particular look at windowSize. Flatlist will continue rendering a "buffer" of items that are offscreen. In your case, the default values of Flatlist are causing your list to render all your images all the time, once you've scrolled far enough down. Since your images are large, this may be your issue.
(2) How often are your Flatlist items updating? You may not be changing the props/state of the component, but the component may still be doing quite a bit of processing. When I render a static list, I usually extend Purecomponent and then return false on shouldComponentUpdate. This is a huge performance boost in general.

How can i remove extra white space in expo BarCodeScanner

iOS is working fine BarCodeScanner take full screen but when i use android there is extra white space.
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this._handleBarCodeScanned}
style={[StyleSheet.absoluteFill, { flex: 1 }]}
/>
I have also checked by giving a different style like but no luck
style={{
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
}}
This seems to be an issue in recent versions of expo-barcode-scanner. One possible workaround is to explicitly set the dimensions of the BarCodeScanner to the dimensions of the screen:
import { Dimensions } from 'react-native';
<BarCodeScanner style={{
width: Dimensions.get('screen').width,
height: Dimensions.get('screen').height,
}} />
Note that setting it to the dimensions of the window, like you tried, does not work.
FrederikVds's answer not worked for me. So I have changed the expo camera which has the barcode scanner functionality too. You can do it like following:
import { Camera } from 'expo-camera'
<Camera
onBarCodeScanned={scanned ? undefined : this._handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
Optionally you can use ratio='16:9'.
If you need to use expo libraries in react-native cli, you should follow these setups
Here is the issue discussion: https://github.com/expo/expo/issues/5212
import { BarCodeScanner, BarCodeScannerResult } from
'expo-barcode-scanner'
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
export default function XYZ() {
return(
<BarCodeScanner
onBarCodeScanned={scanned ? undefined :
handleBarCodeScanned}
style={{ width: height - 188, height: height,
alignSelf: "center" }}
/>
)
}

React Native Webview not loading any url (React native web view not working)

I am trying to implement react native webview component in my application, but the web view is not loading any url its just showing the white page.
var React = require('react-native');
var{
View,
Text,
StyleSheet,
WebView
} = React;
module.exports = React.createClass({
render: function(){
return(
<View style={styles.container}>
<WebView source={{uri: 'https://m.facebook.com'}} style= {styles.webView}/>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex:1,
backgroundColor: '#ff00ff'
},webView :{
height: 320,
width : 200
}
});
Below is the screenshot of the output .
I had this issue. WebView would render when it was the only component returned, but not when nested in another View component.
For reasons I'm not entirely sure of the issue was resolved by setting a width property on the WebView component.
class App extends React.Component {
render() {
return (
<View style={styles.container}>
<WebView
source={{uri: 'https://www.youtube.com/embed/MhkGQAoc7bc'}}
style={styles.video}
/>
<WebView
source={{uri: 'https://www.youtube.com/embed/PGUMRVowdv8'}}
style={styles.video}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'space-between',
},
video: {
marginTop: 20,
maxHeight: 200,
width: 320,
flex: 1
}
});
I'm facing same issue. What I observed is that WebView doesn't work if it's nested. If component returns just WebView, then everything is fine.
Using the answers from other users, I was able to get my react native with webview working both inside a view and outside a view. My problem came down to two things. Being on the android emulator and behind a proxy, I just had to go to my browser (chrome) in the android emulator and sign in to the corporate proxy. Secondly, some sites work and others will not work. Whether the webview was nested or not inside of a View tag, some sites like cnn.com and slack.com etc will work fine, but no matter what settings I tried for google.com it wouldn't work (even though the proxy will definitely allow google.com) Lastly, when I rebuild my application and push to the emulator the new app, sometimes it took an inordinately long time to load any site. But once the site was loaded, the links are quick and responsive. So if you don't at first see something after a build, also be patient. Hope this helps someone else.
My final app.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Dimensions
} from 'react-native';
import { WebView } from 'react-native';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={{flex:1}}>
<WebView
style={styles.webview}
source={{uri: 'https://www.slack.com'}}
javaScriptEnabled={true}
domStorageEnabled={true}
startInLoadingState={false}
scalesPageToFit={true} />
</View>
);
}
}
const styles = StyleSheet.create({
webview: {
flex: 1,
backgroundColor: 'yellow',
width: deviceWidth,
height: deviceHeight
}
});
WebView works well on Android. However you need to enable javascript and dom storage for some web pages.
<WebView style={styles.webView}
source={{uri: 'https://google.com/'}}
javaScriptEnabled={true}
domStorageEnabled={true}
startInLoadingState={true}
>
</WebView>
If you want the component to render the entire page, you need to wrap it with View that has flex: 1. The code below works for me:
<View style={{flex:1, alignItems: 'flex-end'}}>
<WebView
source={{uri: this.state.webContentLink}}
startInLoadingState={true}
scalesPageToFit={true} />
</View>
WebView is being moved to react-native-webview
.
None of the other answers worked except this method:
npm install --save react-native-webview
Then use it as follows:
<View style={{ flex: 1, alignItems: 'flex-end' }}>
<WebView
source={{
uri: 'https://www.yahoo.com',
}}
startInLoadingState={true}
scalesPageToFit={true}
style={{
width: 320,
height: 300,
}}
/>
</View>
<View>
<WebView
source={{uri: this.props.link}}
style={styles.webview}
javaScriptEnabled={true}
domStorageEnabled={true}
startInLoadingState={true}
/>
</View>
and style as follows:
const React = require('react-native');
const { Dimensions } = React;
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
export default {
webview: {
width: deviceWidth,
height: deviceHeight
}
};
All this to deal with bad webview dimension, so just set a specific height and specific width too (deviceHeight and deviceWidth as the example above).
As of June 2020 (noting the date because React Native answers seem to become out-of-date quickly), the simplest solution to this appears to be:
import React from 'react'
import { View, StyleSheet } from 'react-native'
import { WebView } from 'react-native-webview'
export const ComponentWithWebView = () => {
return (
<View style={styles.view}>
<WebView source = {{uri: 'https://www.google.com/'}} />
</View>
)
}
const styles = StyleSheet.create({
view: {
alignSelf: 'stretch',
flex: 1,
}
}
This results in a WebView filling the available space and being nested within a View. I believe the typical problems faced when placing a WebView within a View is that View expects children to force the View to expand (that is, a Text component would take up some amount of width and height which the View then accommodates). WebView, on the other hand, expands to the size of the parent component unless a style is passed specifying the width. Therefore, a simple <View><WebView /></View> results in a 0 width and nothing shown on the screen. The earlier solutions of setting the WebView width work well but require either the device dimensions to be fetched (which might not be the desired width) or for the View to have an onLayout function AND have some way to expand the View to the desired space. I found it easiest to just apply the flex: 1 and alignSelf: 'stretch' for the View to fill the space as desired and then WebView to automatically follow suit.
Hope this helps someone before it becomes obsolete!
I ran into the same issue recently. And I found that
alignment: 'center'
was causing the issue for me. I commented it and the webView got loaded immediately.
I found the solution here :
https://github.com/facebook/react-native/issues/5974
'brunocvcunha's' response worked for me.
Let me give the simplest example which will work seamlessly:
import React from 'react';
import { WebView } from 'react-native';
export default class App extends React.Component {
render() {
return (
<WebView
source={{uri: 'https://github.com/facebook/react-native'}}
/>
);
}
}
Do not add your WebView component within a view that created problem and webview url is not rendered rather styles of view will be shown.
I had the same issue and spent a day attempting to fix it. I copied in the UIExplorer webview example, and that didn't work.
I ultimately ended up upgrading react and creating a new react-native project and copying the files in there, and that fixed it.
I wish I had a better answer as to why that fixed it, but hopefully that helps
Below is piece of the code which worked for me.
render: function(){
return(
<View style={styles.container}>
<WebView url={'https://m.facebook.com'} style= {styles.webView}/>
</View>
);
}
I am doing React Native Webview, Could you please suggest me how to makeWebview loading the uri
render() {
return (
<Modal
animationType="slide"
ref={"webModal"}
style={{
justifyContent: 'center',
borderRadius: Platform.OS === 'ios' ? 30 : 0,
width: screen.width,
height: screen.height,borderColor:'red',
borderWidth: 5
}}
position='center'
backdrop={false}
onClosed={() => {
// alert("Modal closed");
}}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 20, top: 10 }} >
<Text style={{ fontSize: 24, fontWeight: '700' }}>
Interests
</Text>
<Icon name="ios-close" size={40} color='purple' onPress={() => { this.refs.webModal.close() }} />
</View>
<WebView
source={{ uri: this.state.link }}
style={{ marginTop: 20,borderColor:'green',
borderWidth: 5 }}
/>
</Modal>
);
}
}
import { WebView } from 'react-native'; is deprecated
use below line instead
npm install react-native-render-html#4.1.2 --save
then
import HTML from 'react-native-render-html';
react-native-render-html starting with version 4.2.0, react-native-webview is now a peer dependency. As a result, you need to install it yourself.
Try
<WebView
source={{ uri: "https://inhall.in/" }}
style={Styles.webView}
javaScriptEnabled={true}
scalesPageToFit />
javaScriptEnabled={true} might help