### Summary
I am trying to take a picture with expo-imagepicker, save the pictu…re to the filesystem, and load the picture into an `<ImageBackground />` element within my app. **In production only** the app crashes after taking the picture and clicking the ✅ to confirm the picture.
### Managed or bare workflow? If you have `ios/` or `android/` directories in your project, the answer is bare!
managed
### What platform(s) does this occur on?
Android
### SDK Version (managed workflow only)
44
### Environment
Expo CLI 5.0.3 environment info:
System:
OS: macOS 11.4
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 14.18.0 - /usr/local/bin/node
Yarn: 1.22.17 - /usr/local/bin/yarn
npm: 6.14.15 - /usr/local/bin/npm
Watchman: 20210102.202219.0 - /usr/local/bin/watchman
SDKs:
Android SDK:
API Levels: 29, 30
Build Tools: 29.0.2, 30.0.2
System Images: android-29 | Google APIs Intel x86 Atom, android-30 | Google APIs Intel x86 Atom
IDEs:
Android Studio: 2020.3 AI-203.7717.56.2031.7784292
Xcode: /undefined - /usr/bin/xcodebuild
npmPackages:
babel-preset-expo: 9.0.1 => 9.0.1
expo: ^44.0.0 => 44.0.1
react: 17.0.1 => 17.0.1
react-dom: 17.0.1 => 17.0.1
react-native: 0.64.3 => 0.64.3
react-native-web: 0.17.1 => 0.17.1
npmGlobalPackages:
eas-cli: 0.42.4
Expo Workflow: bare
### Reproducible demo
Here is a snack of a mvp that crashes on android once in production (app store or apk): https://snack.expo.dev/@lastof/github.com-lastofthefirst-expo-image-crasher
This code does not crash the application:
```jsx
import React, { useState, useEffect } from "react";
import { Button, Image, View, Platform } from "react-native";
import * as ImagePicker from "expo-image-picker";
export default function ImagePickerExample() {
const [image, setImage] = useState([]);
const [status, requestPermission] = ImagePicker.useCameraPermissions();
const TakeImage = async () => {
let permission = await ImagePicker.getCameraPermissionsAsync();
if (!permission) {
return;
}
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
// allowsEditing: true,
aspect: [4, 3],
quality: 1,
base64:true,
});
if (!result.cancelled) {
let arr = image;
arr = [...arr, result.uri];
setImage(arr);
}
};
const pickImage = async () => {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
// allowsEditing: true,
aspect: [4, 3],
quality: 1,
base64:true,
});
console.log(result);
if (!result.cancelled) {
let arr = image;
arr = [...arr, result.uri];
setImage(arr);
}
};
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Button title="Pick an image from camera roll" onPress={pickImage} />
<Button title="Take a picture" onPress={TakeImage} />
{image &&
image.map((el) => {
return (
<Image
key={el}
source={{ uri: el }}
style={{ width: 200, height: 200 }}
/>
);
})}
</View>
);
}
```
However this version does crash the application:
```jsx
import React, { useState, useEffect } from "react";
import { Button, Text, View, ImageBackground, ScrollView } from "react-native";
import * as ImagePicker from "expo-image-picker";
import uuidV4 from "./utility/uuid";
import * as FileSystem from "expo-file-system";
import AsyncStorage from "@react-native-async-storage/async-storage";
const getData = async (key) => {
try {
const jsonValue = await AsyncStorage.getItem(key);
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch (e) {
// error reading value
}
};
const storeData = async (key, value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(key, jsonValue);
} catch (e) {
// saving error
}
};
export default function ImagePickerExample() {
const [statusCam, requestCamPermission] = ImagePicker.useCameraPermissions();
const [statusMedia, requestMediaPermission] =
ImagePicker.useMediaLibraryPermissions();
let [images, setImages] = useState([]);
useEffect(() => {}, []);
useEffect(async () => {
let result = await getData("@images");
if (result) {
setImages(result);
} else {
await storeData("@images", []);
}
}, []);
useEffect(async () => {
await storeData("@images", images);
}, [images]);
let reset = async () => {
const imagesDir = FileSystem.documentDirectory + "images/";
await FileSystem.deleteAsync(imagesDir);
setImages([]);
};
let saveImage = async (image) => {
// This represents the directory we are putting all images into.
let file = await FileSystem.getInfoAsync(
FileSystem.documentDirectory + "images/"
);
let uuid = uuidV4();
// If this dir isnt created yet, make it
!file.exists &&
(await FileSystem.makeDirectoryAsync(
FileSystem.documentDirectory + "images/",
{ intermediates: true }
)) &&
console.log("made images Directory");
// we are creating a file name.
let filename = `images/${uuid}.jpg`;
// add the uri to the list.
//writing the image to the filesystem.
await FileSystem.writeAsStringAsync(
FileSystem.documentDirectory + `images/${uuid}.jpg`,
image.base64,
{ encoding: FileSystem.EncodingType.Base64 }
);
return FileSystem.documentDirectory + `images/${uuid}.jpg`;
};
//
const TakeImage = async () => {
requestMediaPermission();
requestCamPermission();
let stored = await getData("@images");
if (!statusCam || !statusMedia) {
console.log("no permission");
return;
} else {
let { status } = await ImagePicker.getCameraPermissionsAsync();
console.log(status);
}
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
// allowsEditing: true,
aspect: [4, 3],
quality: 0.5,
base64: true,
});
if (!result.cancelled) {
let uri = await saveImage(result);
setImages([...stored, uri]);
}
};
const pickImage = async () => {
requestMediaPermission();
let stored = await getData("@images");
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
// allowsEditing: true,
aspect: [4, 3],
quality: 0.5,
base64: true,
});
console.log(result);
if (!result.cancelled) {
let uri = await saveImage(result);
setImages([...stored, uri]);
}
};
return (
<ScrollView>
<View style={{marginTop:200, flex: 1, alignItems: "center", justifyContent: "center" }}>
<Button onPress={reset} title="reset"></Button>
<Button onPress={() => console.log(images)} title="Log"></Button>
<Button title="Pick an image from camera roll" onPress={pickImage} />
<Button title="Take a picture" onPress={TakeImage} />
</View>
{images &&
images.map((el) => {
return (
<ImageBackground
key={el}
source={{ uri: el }}
style={{ width: 200, height: 200 }}
>
<Text style={{ color: "white" }}>{el}</Text>
</ImageBackground>
);
})}
</ScrollView>
);
}
```