Accessing Camera Roll Using React Native
This Guide fills gaps in the React Native documentation in regards to taking a picture, accessing the iOS Camera Roll, authentication, and more.
Sep 3, 2020 • 8 Minute Read
Introduction
When learning React Native, we find that majority of issues are encountered while trying to implement features such as taking a picture, accessing photos from the mobile device, chats, authentication, etc. These issues are a bit hard to resolve as the React Native documentation does not explain these concepts very well. Thus, we have to use libraries to achieve any of the above functionalities.
In this guide, we will highlight the features implemented using React Native APIs. This guide will help you implement the camera roll API for accessing pictures on a device. Feel free to also check out the official React Native documentation.
Setting up React Native
For someone just starting to build React Native apps, this should be a fairly simple guide to get started with. We'll be building our app for IOS, so the setup is according to that platform. We can go to the React Native site and follow the steps to build projects with native code.
Also for a quick setup, we can use the create-react-native-app.
By now, the app should be up and running on either the emulator or iPhone device. Below is how the folder structure should look. We have a component folder with three components as below:
-
CamScreen.js - The add picture button and accessing the camera roll take place here.
-
ViewPictures.js - Displays pictures from your iPhone.
-
SelectedPicture.js - Displays the selected picture.
We have the boilerplate code in our index.ios.js. It should look something like this:
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import CamScreen from './component/CamScreen';
export default class camRollExample extends Component {
render() {
return (
<CamScreen/>
);
}
}
AppRegistry.registerComponent('camRollExample', () => camRollExample);
In CamScreen.js, we have a simple interface where we have the add picture button, and we also import the CameraRoll module from React Native.
CamScreen.js
import React, { Component } from 'react';
import {
CameraRoll,
Image,
StyleSheet,
TouchableHighlight,
View,
} from 'react-native';
class CamScreen extends Component {
render() {
return (
<View style={styles.container}>
<TouchableHighlight>
<Image
source={require('../assets/addPicture.png')} />
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
});
export default CamScreen;
Accessing Photos
For accessing photos, we need a click event. Let's add the onPress prop to the button and a handler method called getPicturesFromGallery().
//...
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={() => this.getPicturesFromGallery()}>
<Image
source={require('../assets/addPicture.png')} />
</TouchableHighlight>
</View>
);
}
getPicturesFromGallery()
//...
getPicturesFromGallery() {
CameraRoll.getPhotos({ first: 5000 })
.then(res => {
console.log(res, "images data")
})
}
//...
The object inside the getPhotos({ first: 5000 }) is used to specify the number of images that we want to get from the gallery. When we run the app, we'll encounter an error:
"Cannot read property 'getPhotos' of undefined"
The above error happens because the camera roll library has not been added or linked to our build phases in Xcode. To fix the error, we'll:
-
Go to our project directory
-
Open IOS directory
-
Navigate to the file that has .xcodeproj as the extension. In our case, it should be camRollExample.xcodeproj
-
Open this file in Xcode.
Next, we should drag RCTCamRoll.xcodeproj in our project directory to Xcode.
Let's drag the RCTCamRoll.xcodeproj file to libraries file in Xcode. We can then click on Build Phases located in the top right-hand corner in Xcode. Let's click the dropdown next to Link Binary With Libraries, then the + sign to add libRCTCamRoll.a.
We can then run the build and restart our emulator or device. The image object should be visible in our log. To check the images, we need to have the uri in the image object. Here is an updated version of CameraRoll.js.
CameraRoll.js
//...
import ViewPictures from './ViewPictures';
class CamScreen extends Component {
state = {
showPhotoGallery: false,
pictureArray: []
}
getPicturesFromGallery() {
CameraRoll.getPhotos({ first: 5000})
.then(res => {
let pictureArray = res.edges;
this.setState({ showPhotoGallery: true, pictureArray: pictureArray })
})
}
render() {
if (this.state.showPhotoGallery) {
return (
<ViewPictures
pictureArray={this.state.pictureArray} />
)
}
return (
<View style={styles.container}>
<TouchableHighlight
onPress={() => this.getPicturesFromGallery()}>
<Image
source={require('../assets/addPicture.png')} />
</TouchableHighlight>
</View>
);
}
}
//...
In the above code snippets, we just imported ViewPictures.js. This is for displaying the images inside of a list view.
ViewPictures.js
import React, { Component } from 'react';
import {
Image,
View,
ListView,
StyleSheet,
Text,
TouchableHighlight
} from 'react-native';
import SelectedPicture from './SelectedPicture';
class ViewPictures extends Component {
state = {
ds: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
}),
showSelectedPicture: false,
uri: ''
}
renderRow(rowData) {
const { uri } = rowData.node.image;
return (
<TouchableHighlight
onPress={() => this.setState({ showSelectedPicture: true, uri: uri })}>
<Image
source={{ uri: rowData.node.image.uri }}
style={styles.image} />
</TouchableHighlight>
)
}
render() {
const { showSelectedPicture, uri } = this.state;
if (showSelectedPicture) {
return (
<SelectedPicture
uri={uri} />
)
}
return (
<View style={{ flex: 1 }}>
<View style={{ alignItems: 'center', marginTop: 15 }}>
<Text style={{ fontSize: 30, fontWeight: '700' }}>Pick A Picture !</Text>
</View>
<ListView
contentContainerStyle={styles.list}
dataSource={this.state.ds.cloneWithRows(this.props.pictureArray)}
renderRow={(rowData) => this.renderRow(rowData)}
enableEmptySections={true} />
</View>
);
}
}
const styles = StyleSheet.create({
list: {
flexDirection: 'row',
flexWrap: 'wrap'
},
image: {
width: 120,
height: 130,
marginLeft: 15,
marginTop: 15,
borderRadius: 6,
borderWidth: 2,
borderColor: '#efefef'
}
})
export default ViewPictures;
When we click or select a picture from the list, the selected picture will get displayed in the SelectedPicture.js component.
SelectedPicture.js
import React from 'react';
import {
Image,
View,
StyleSheet,
Text,
TouchableHighlight
} from 'react-native';
const SelectedPicture = (props) => {
const { uri } = props;
return (
<View style={styles.container}>
<Image
source={{uri: uri}}
style={styles.image}/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
image: {
height: 300,
width: 200
}
});
export default SelectedPicture;
Conclusion
Having run the app on both iPhone 6s and iPhone 6s plus, we can extend the test to other devices and verify how it performs on other platforms.