Using React Native Camera in your app

Written by Carlos Angarita, Software Engineer

From reading barcodes to adding multimedia or AR capabilities, the phone camera is very useful in a multitude of scenarios. So how can we tap these capabilities in a React Native app? A great option is by using a community package called React Native Camera.


Getting Started


We are going to start by creating a new React Native project, let's call it AwesomeCamera!


    
npx react-native init AwesomeCamera
cd AwesomeCamera
npx react-native run-android # or run-ios
    
  

Now that we have a clean project to start working on, we need to install a couple of packages to get things going! First, the previously mentioned React Native Camera and a Vector Icon library to get a nice camera icon for our app.


    
npm install --save react-native-vector-icons react-native-camera
cd ios && pod install && cd ..
npx react-native link react-native-vector-icons
    
  

And we need to set up permissions for both Android and iOS. In the case of Android, we need to go to the android/app/src/main/AndroidManifest.xml file and add


    
<!-- Required --> 
<uses-permission android:name="android.permission.CAMERA" /> 
<!-- Include this only if you are planning to use the microphone for video recording --> 
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- Include this only if you are planning to use the camera roll --> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    
  

And we also need to include a few lines at android/app/build.gradle


    
android { 
 ... 
 defaultConfig { 
  ... 
  missingDimensionStrategy 'react-native-camera', 'general' // <--- insert this line 
 }
}
    
  

In the case of iOS we just need to edit ios/AwesomeCamera/Info.plist and add inside <dict>


    
<!-- Required with iOS 10 and higher --> 
<key>NSCameraUsageDescription</key> 
<string>Your message to user when the camera is accessed for the first time</string> 
<!-- Required with iOS 11 and higher: include this only if you are planning to use the camera roll --> 
<key>NSPhotoLibraryAddUsageDescription</key> 
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the camera roll --> 
<key>NSPhotoLibraryUsageDescription</key> 
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the microphone for video recording --> 
<key>NSMicrophoneUsageDescription</key> 
<string>Your message to user when the microphone is accessed for the first time</string>
    
  

For our current example, we just need access to the camera so no microphone or photo library access is required. Let’s start with the Camera component. On the components/Camera.js we’ll have

    
import React, {PureComponent} from 'react';
import {RNCamera} from 'react-native-camera';

export default class Camera extends PureComponent {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <RNCamera
        ref={ref => {
          this.camera = ref;
        }}
        captureAudio={false}
        style={{flex: 1}}
        type={RNCamera.Constants.Type.back}
        androidCameraPermissionOptions={{
          title: 'Permission to use camera',
          message: 'We need your permission to use your camera',
          buttonPositive: 'Ok',
          buttonNegative: 'Cancel',
        }} />
    );
  }
}
    
  

To clarify what we have here let's look prop by prop.


    
ref={ref => {
    this.camera = ref;
}}
    
  

The ref gives us access to an instance of the camera component


    
type={RNCamera.Constants.Type.back}
    
  

Lets us decide which camera to use, if front or back

    
androidCameraPermissionOptions={{
    title: 'Permission to use camera',
    message: 'We need your permission to use your camera',
    buttonPositive: 'Ok',
    buttonNegative: 'Cancel',
}}
    
  

Allows us to config the permissions message on android.


    
captureAudio={false}
    
  

Because we don't need to record audio for this example we set this option so a permission message doesn't pop up.


    
style={{flex: 1}}
    
  

We ask the camera to cover the container space. Now we are going to replace the App.js content with

    
import React from 'react';
import Camera from './components/Camera';
import {SafeAreaView} from 'react-native';

const App = () => {
  return (
    <>
      <SafeAreaView styles={{flex:1}}>
        <Camera />
      </SafeAreaView>
    </>
  );
};

export default App;
    
  

And now we have our camera working! You should get a prompt to request permissions in your device or emulator and then get access to the camera.


Using your webcam as the camera of your emulator


The Android emulator comes with a nice feature that allows developers to use your laptop's webcam as the emulated device camera. To configure this we need to open Android Studio and search for the AVD Manager. We need to click on the pencil icon for the device we are emulating and that opens the Virtual Device Configuration screen. Then click on the Show Advanced Settings and the Camera option is now available for edition. It has two options Front and Back to decide which camera we are going to use, so click on the dropdown for the Back camera and select the Webcam0 option and then Finish. If you have the emulator running, you should restart it to apply the configuration. Unfortunately for the iOS simulator there is no similar option that I'm aware of, so you need to test things in a real device.


Taking a picture


Now that we have access to the camera, it is time to take a picture! So we are going to add a button to get the picture when pressed. Our components/Camera.js is going to look something like this

    
import React, {PureComponent} from 'react';
import {RNCamera} from 'react-native-camera';

import Icon from 'react-native-vector-icons/dist/FontAwesome';
import {TouchableOpacity, Alert, StyleSheet} from 'react-native';


export default class Camera extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      takingPic: false,
    };
  }

  takePicture = async () => {
    if (this.camera && !this.state.takingPic) {
       
      let options = {
        quality: 0.85,
        fixOrientation: true,
        forceUpOrientation: true,
      };

      this.setState({takingPic: true});

      try {
        const data = await this.camera.takePictureAsync(options);
        Alert.alert('Success', JSON.stringify(data));
      } catch (err) {
        Alert.alert('Error', 'Failed to take picture: ' + (err.message || err));
        return;
      } finally {
        this.setState({takingPic: false});
      }

    }
  };

  render() {
    return (
      <RNCamera
        ref={ref => {
          this.camera = ref;
        }}
        captureAudio={false}
        style={{flex: 1}}
        type={RNCamera.Constants.Type.back}
        androidCameraPermissionOptions={{
          title: 'Permission to use camera',
          message: 'We need your permission to use your camera',
          buttonPositive: 'Ok',
          buttonNegative: 'Cancel',
        }}>
        <TouchableOpacity
          activeOpacity={0.5}
          style={styles.btnAlignment}
          onPress={this.takePicture}>
          <Icon name="camera" size={50} color="#fff" />
        </TouchableOpacity>
      </RNCamera>
    );
  }
}

const styles = StyleSheet.create({
  btnAlignment: {
      flex: 1,
      flexDirection: 'column',
      justifyContent: 'flex-end',
      alignItems: 'center',
      marginBottom: 20,
  },
});
    
  

While we added quite a few things here, the truth is we just need to focus on the takePicture async function that is called when pressing the camera icon. This function checks that we have a ref for our RNCamera component and that no picture is being processed currently. Next, it calls the takePictureAsync function that the RNCamera object gives us and once the picture is taken, returns an object with the photo info.


React Native Camera after taking a photo.

Accessing the picture


As we can see from the screenshot, inside the object we have an uri property with the direction of the file – let’s put it to use. In our App.js file, we are going to have the following

    
import React, {useState} from 'react';
import Camera from './components/Camera';
import {SafeAreaView, TouchableHighlight, Image} from 'react-native';

const App = () => {
  const [img, setImg] = useState(null);

  function onPicture({uri}) {
    setImg(uri);
  }

  function onBackToCamera() {
    setImg(null);
  }

  return (
    <>
      <SafeAreaView style={{flex: 1}}>
        {img ? (
          <TouchableHighlight
            style={{flex: 1}}
            onPress={() => {
              onBackToCamera();
            }}>
            <Image source={{uri: img}} style={{flex: 1}} />
          </TouchableHighlight>
        ) : (
          <Camera onPicture={onPicture} />
        )}
      </SafeAreaView>
    </>
  );
};

export default App;
    
  

We are passing a prop to our Camera component so when a picture is taken we are notified; therefore, we replace the success Alert with the onPicture


    
- Alert.alert('Success', JSON.stringify(data));
+ this.props.onPicture(data);
    
  

The onPicture function gets a data object and destructures it to find the uri and store it as part of the component state; we are using that uri to access the file and show it using the Image component. Now if we have an image the camera will go away, and if we tap the image the camera will come back!


Accessing the picture


Thank you for reading. I hope it has been helpful as an introduction to the React Native Camera package. This component is very powerful and can handle things like making videos, reading barcodes, and even doing face and text recognition. Hopefully, this tutorial will help you add more value to your app!


---
At FullStack Labs, we are consistently asked for ways to speed up time-to-market and improve project maintainability. We pride ourselves on our ability to push the capabilities of these cutting-edge libraries. Interested in learning more about speeding up development time on your next form project, or improving an existing codebase with forms? Contact us.

Let’s Talk!

We’d love to learn more about your project. Contact us below for a free consultation with our CEO.
Projects start at $25,000.

FullStack Labs
This field is required
This field is required
Type of project
Reason for contact:
How did you hear about us? This field is required