I want save one of views in my react native app as an image to camera roll. I'm using camera roll to save image. I got alert "Image saved successfully" but at the same time on the screen displayed error: " Possible Unhandled Promise Rejection (id: 2): Error: /cacheDir/rn_image_picker_lib_temp_aefbf48e-3b44-461e-a9ec-d51ce0aefb4c.jpg: open failed: ENOENT (No such file or directory)...".
Below I paste code of my UploadScreen class. The image was saved, but the size of file is equal 0 bytes and I can't open it.
Someone could help me?
Thanks in advance
I added dependecy to Android Manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
This is my imported library:
import React from 'react';
import { Text, TextInput, View, Button, Image, ImageBackground, StyleSheet, Alert, PermissionsAndroid } from 'react-native';
import { createAppContainer, StackNavigator } from 'react-navigation';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createStackNavigator } from 'react-navigation-stack';
import Icon from 'react-native-vector-icons/FontAwesome';
import DialogAndroid from 'react-native-dialogs';
import Sound from 'react-native-sound';
import * as ImagePicker from 'react-native-image-picker';
import CameraRoll from '@react-native-community/cameraroll';
Upload Screen code:
class UploadScreen extends React.Component {
constructor(props) {
super(props)
this.state = {
filepath: {
data: '',
uri: ''
},
fileData: '',
fileUri: ''
}
}
static navigationOptions = ({ navigation }) => ({
headerShown: false
});
showContact = () => {
Sound.setCategory('Playback');
var mySound = new Sound('sound.mp3', Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log('Blad wczytywania: ' + error);
return;
}
else {
mySound.play((success) => {
if (success) {
console.log('Odtwarzanie')
}
})
}
});
mySound.setVolume(1.0);
mySound.release();
}
showDescription = () => {
Sound.setCategory('Playback');
var mySound = new Sound('sound.mp3', Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log('Blad wczytywania: ' + error);
return;
}
else {
mySound.play((success) => {
if (success) {
console.log('Odtwarzanie')
}
})
}
});
mySound.setVolume(1.0);
mySound.release();
Alert.alert('Aplikacja do generowania wlasnych memow', '1. Przeslij swoje zdjecie lub wybierz z jedno z dostepnych. \n 2. Napisz tekst. \n 3. Zapisz utworzony mem. \n\ 4. Udostepnij na swoich social mediach.');
}
selectImage = () => {
let options = {
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.launchImageLibrary(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
alert(response.customButton);
} else {
const source = { uri: response.uri };
console.log('response', JSON.stringify(response));
this.setState({
filePath: response,
fileData: response.data,
fileUri: response.uri
});
}
});
}
takePhoto = () => {
let options = {
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.launchCamera(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
alert(response.customButton);
} else {
const source = { uri: response.uri };
console.log('response', JSON.stringify(response));
this.setState({
filePath: response,
fileData: response.data,
fileUri: response.uri
});
}
});
}
renderImage() {
if (this.state.fileUri) {
return <Image ref="meme" source={{ uri: this.state.fileUri }}
style={{ width: '100%', height: '100%', resizeMode: 'cover' }}
/>
} else {
return <Image ref="meme" source={require('./sources/1.jpg')}
style={{ width: '100%', height: '100%', resizeMode: 'cover' }}
/>
}
}
state = {
top: '',
bottom: '',
};
getPermissionAndroid = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
{
title: 'Image Save Permission',
message: 'Your permission is required to save images to your device',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
return true;
}
Alert.alert(
'',
'Your permission is required to save images to your device',
[{ text: 'OK', onPress: () => { } }],
{ cancelable: false },
);
} catch (err) {
console.log('err', err);
}
};
onSaveImage = async () => {
try {
var uri = this.state.fileUri;
console.log(uri);
if (Platform.OS === 'android') {
const granted = this.getPermissionAndroid;
if (!granted) {
return;
}
}
const image = CameraRoll.save(uri, 'photo');
if (image) {
Alert.alert(
'',
'Image saved successfully.',
[{ text: 'OK', onPress: () => { } }],
{ cancelable: false },
);
}
} catch (error) {
console.log('error', error);
}
};
render() {
const { navigate } = this.props.navigation;
const { top, bottom } = this.state;
return (
<View
style={{
flex: 1,
}}>
<ImageBackground style={styles.imgBackground}
resizeMode='cover'
source={require('./sources/background.jpg')}>
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-end',
}}>
<Icon.Button style={{ right: -4 }}
name="info-circle"
onPress={this.showDescription} >
</Icon.Button>
<Icon.Button style={{ right: -4 }}
name="home"
onPress={() => navigate('Home')}
>
</Icon.Button>
<Icon.Button style={{ right: -6 }}
name="at"
onPress={this.showContact}
>
</Icon.Button>
</View>
<View style={{ flex: 2, alignItems: 'center', justifyContent: 'space-between', }}>
<TextInput underlineColorAndroid={'transparent'} style={styles.input} value={top} onChangeText={(top) => this.setState({ top })} placeholder={'Input top text here'} />
<TextInput underlineColorAndroid={'transparent'} style={styles.input} value={bottom} onChangeText={(bottom) => this.setState({ bottom })} placeholder={'Input bottom text here'} />
</View>
<View style={{ flex: 5, alignItems: 'center', justifyContent: 'space-between', }}>
{this.renderImage()}
<Text style={ styles.memeTop }>{top}</Text>
<Text style={styles.memeBottom}>{bottom}</Text>
</View>
<View style={{ flex: 2, alignItems: 'center', justifyContent: 'space-between', margin: 5}}>
<Button title="Select image file"
onPress={this.selectImage}
/>
<Button title="Take a photo"
onPress={this.takePhoto}
/>
<Button title="Save result"
//onPress={() => navigate('Result')}
onPress={this.onSaveImage}
/>
</View >
<View style={{ flex: 0.3 }}>
<Text style={{
fontFamily: 'Impact', fontWeight: 'bold', fontSize: 10, textAlign: 'right', alignSelf: 'flex-end',
textShadowColor: 'black', textShadowOffset: { width: 10, height: 5 }, textShadowRadius: 10,
color: 'white', position: 'absolute', bottom: 0
}}>
Copyright all right reserved {'\u00A9'} 2021 Marek Przybylowski
</Text>
</View >
</ImageBackground>
</View>
);
}
}