How to Build a React Native QR Scanner: An RNCamera Tutorial

Capture picture-perfect moments with ease using the camera functionality in React Native. In this comprehensive tutorial, we’ll walk you through the process of integrating camera features into your app, from capturing photos and videos to applying filters and accessing device-specific functionalities. Let’s dive in and unleash the power of React Native camera!

In this React Native QR code scanner tutorial, the app we create will be able to read QR codes in real-time and render their content to the screen at the time of detection. We will be using React Native’s CLI Quickstart.

(Note: If you need help setting this up, you can always refer to the React Native Getting Started page—don’t forget to click on the “React Native CLI Quickstart” button, as “Expo CLI Quickstart” comes preselected at the time of writing this article.)

Why a React Native Scanner?

React Native is a valuable framework that borrows React’s paradigm and design principles to enable lightning fast, cross-platform development of snappy UIs. Facebook, Airbnb, Uber, and many others already have their latest apps built with React Native.

What Is React Native Camera?

React Native Camera (RNCamera) is the go-to component when it comes to implementing camera functionality in a React Native app. This component helps you communicate with the native OS through some simple functions so you can use device hardware. You can build your apps around these functions without getting into the hassle of native code. RNCamera already supports:

  • Photographs
  • Videos
  • Face detection
  • Barcode scanning
  • Text recognition (Android only)

Note that RNCamera used to come in two flavors:

  1. RNCamera
  2. RCTCamera (deprecated)

…so make sure to use RNCamera so that you can keep getting the latest updates.

Note: React Native Camera is heavily based on the Expo camera module and going back and forth between the two is pretty easy.

Creating Your First App Using RNCamera

Before we begin our React Native QR scanner, there are some dependencies we’ll need to install.

Installing RNCamera’s Dependencies

Our setup needs a minimum of JDK version 1.7 (which you most likely have) and if you’re on Android you’ll require buildToolsVersion newer than 25.0.2. (To be sure, there is a more detailed and up-to-date list in the docs.)

First let’s get started by creating a new React Native project:

react-native init CameraExample

Now let’s deploy the first version of our React Native QR scanner example over our phone.

cd CameraExample
react-native run-android

Now it’s time to install the react-native-camera package in our project. We will use the “Mostly automatic install with react-native” option. (There are others like Mostly automatic install with CocoaPods and Manual install, but we will stick to the first option, as it’s the most efficient.) Simply run:

npm install react-native-camera --save
react-native link react-native-camera

You must also add the following permissions to android/app/src/main/AndroidManifest.xml:

   package="com.cameraexample">

     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

     <application
       android:name=".MainApplication"

You’ll also need to set the dimension strategy in android/app/build.gradle—it has no default and you’ll get an error if you don’t define it:

     defaultConfig {
         applicationId "com.cameraexample"
         minSdkVersion rootProject.ext.minSdkVersion
+        missingDimensionStrategy 'react-native-camera', 'general'
         targetSdkVersion rootProject.ext.targetSdkVersion
         versionCode 1
         versionName "1.0"

Note: The dimension strategy should normally be set to general as above. However, you can set it to mlkit instead, if you’d like to use MLKit for text/face/barcode recognition.

After the installation, you will need to use run-android to install the new dependencies:

react-native run-android

If everything went well, you should see the same React Native welcome screen on your device or simulator again.

Setting Up the Camera

First, let’s start by modifying App.js and importing RNCamera there:

import { RNCamera } from 'react-native-camera';

Next, we’ll modify the render function to include our newly imported RNCamera. Notice the style attribute added to the camera in order for it to take the full screen. Without these styles, you may not be able to see the camera render on your screen, as it will not occupy any space:

   render() {
     return (
       <View style={styles.container}>
-        <Text style={styles.welcome}>Welcome to React Native!</Text>
-        <Text style={styles.instructions}>To get started, edit App.js</Text>
-        <Text style={styles.instructions}>{instructions}</Text>
+        <RNCamera
+          ref={ref => {
+            this.camera = ref;
+          }}
+          style={{
+            flex: 1,
+            width: '100%',
+          }}
+        >
+        </RNCamera>
       </View>
     );
   }

After adding this code, your interface should have the camera on, full-screen, just like the screenshot below:

Now our React Native barcode scanner can see barcodes (as we can see our test QR codes showing on the monitor above) but can’t read them yet. Let’s use RNCamera’s algorithm to recognize what is written inside each of them.

Reading Barcode Information

In order to read barcode information, we will use the onGoogleVisionBarcodesDetected prop so that we can call a function and extract the information. Let’s add that in the <RNCamera> component and link it to a barcodeRecognized function to take care of it. Note that onGoogleVisionBarcodesDetected returns an object containing the barcodes property, which contains an array of all the barcodes recognized in the camera.

Note: The onGoogleVisionBarcodesDetected QR code technology is only available on Android, but if you’d like a cross-platform approach, you’d better go with onBarCodeRead. It supports only a single barcode at a time—using it as a fallback is left as an exercise for the reader.

Here’s how our <RNCamera> should look after adding onGoogleVisionBarcodesDetected:

       <RNCamera
          ref={ref => {
            this.camera = ref;
          }}
          style={{
            flex: 1,
            width: '100%',
          }}
          onGoogleVisionBarcodesDetected={this.barcodeRecognized}
        >
        </RNCamera>

And now we can handle the barcodes in App.js with the function below, which will only warn us when a barcode is detected and should display its content on the screen:

  barcodeRecognized = ({ barcodes }) => {
    barcodes.forEach(barcode => console.warn(barcode.data))
  };
Rendering Barcode Overlays

The previous screenshot now shows the information contained in the barcode but does not allow us to know which message belongs to which barcode. For this, we will go deeper into the barcodes returned from onGoogleVisionBarcodesDetected and try to pinpoint each of the barcodes on our screen.

But first, we will need to save the recognized barcodes into the state so that we can access it and render an overlay based on the contained data. We will now modify our previously defined function to look like this:

barcodeRecognized = ({ barcodes }) => this.setState({ barcodes });

We will now need to add a state object initialized to an empty array of barcodes so that it doesn’t create any errors in our render functions:

export default class App extends Component<Props> {
  state = {
    barcodes: [],
  }
// ...

Let’s now create the renderBarCodes function which should be added inside the <RNCamera> component:

        <RNCamera
          ref={ref => {
            this.camera = ref;
          }}
          style={{
            flex: 1,
            width: '100%',
          }}
          onGoogleVisionBarcodesDetected={this.barcodeRecognized}
        >
          {this.renderBarcodes()}
        </RNCamera>

This function should now take the barcodes recognized from the state and show them on-screen:

  renderBarcodes = () => (
    <View>
      {this.state.barcodes.map(this.renderBarcode)}
    </View>
  );

Notice that the mapping is pointed to renderBarcode which should render each barcode on the screen. I’ve added some minor styling in order for us to be able to recognize those easily:

 renderBarcode = ({ bounds, data }) => (
    <React.Fragment key={data + bounds.origin.x}>
      <View
        style={{
          borderWidth: 2,
          borderRadius: 10,
          position: 'absolute',
          borderColor: '#F00',
          justifyContent: 'center',
          backgroundColor: 'rgba(255, 255, 255, 0.9)',
          padding: 10,
          ...bounds.size,
          left: bounds.origin.x,
          top: bounds.origin.y,
        }}
      >
        <Text style={{
          color: '#F00',
          flex: 1,
          position: 'absolute',
          textAlign: 'center',
          backgroundColor: 'transparent',
        }}>{data}</Text>
      </View>
    </React.Fragment>
  );

Each barcode recognized has:

  • bounds property to tell us where on our screen the barcode was found, which we’ll use to render the overlay for it
  • data property that shows us what is encoded in that specific barcode
  • type property which tells us what kind of barcode it is (2D, QR, etc.)

Using those three parameters as we have in the render function above gives the following result:

 

By following this comprehensive tutorial, you’ll be equipped with the knowledge and skills to integrate camera functionality into your React Native app seamlessly. Remember to experiment with different features and customize the implementation according to your app’s requirements. Get ready to wow your users with stunning images and videos captured within your app!