QR Code Scanning in React-Native 0.71

Romario Fitzgerald
4 min readJun 10, 2023
Photo by Markus Winkler on Unsplash

If you’re here you’ve probably tried all the old methods of scanning QR codes in react-native that no longer work. I’m glad you’ve found this post :)
You’ve made the right choice with React-Native Vision Camera and Vision Camera Code Scanner.

There’s a slight catch, though — they need some tweaks to play nicely with React-Native 0.71. But don’t worry, we’ve got you covered with a step-by-step guide to iron out these quirks and unlock the full potential of these libraries.

And once we’ve got these libraries behaving, we’ll also show you how to whip up a nifty QR code reader. So buckle up and let’s get rolling!

Step 1: Equip Your Toolkit with patch-package

First things first, let’s get patch-package into our toolkit. This trusty tool helps us apply the necessary patches to our npm dependencies, like a pro. Add it to your project with:

npm install patch-package

or, if you prefer yarn:

yarn add patch-package

Remember, patch-package is a tool for your developer's kit, you won't need it in the production build!

Step 2: Smoothing Out React-Native Vision Camera

Now, let’s get react-native-vision-camera in line. Create a new file in your project's root directory and name it react-native-vision-camera+2.15.4.patch. Add the following content:


diff --git a/node_modules/react-native-vision-camera/android/build.gradle b/node_modules/react-native-vision-camera/android/build.gradle
index 91e64d9..579ed1f 100644
--- a/node_modules/react-native-vision-camera/android/build.gradle
+++ b/node_modules/react-native-vision-camera/android/build.gradle
@@ -50,7 +50,7 @@ def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME").split("\\
def FOR_HERMES = System.getenv("FOR_HERMES") == "True"
rootProject.getSubprojects().forEach({project ->
if (project.plugins.hasPlugin("com.android.application")) {
- FOR_HERMES = REACT_NATIVE_VERSION >= 71 && project.hermesEnabled || project.ext.react.enableHermes
+ FOR_HERMES = REACT_NATIVE_VERSION >= 71 && project.hermesEnabled.toBoolean() || project.ext.react.enableHermes
}
})
def jsRuntimeDir = {
diff --git a/node_modules/react-native-vision-camera/android/src/main/cpp/MakeJSIRuntime.h b/node_modules/react-native-vision-camera/android/src/main/cpp/MakeJSIRuntime.h
index 39045bd..c135caf 100644
--- a/node_modules/react-native-vision-camera/android/src/main/cpp/MakeJSIRuntime.h
+++ b/node_modules/react-native-vision-camera/android/src/main/cpp/MakeJSIRuntime.h
@@ -12,7 +12,7 @@
#include <hermes/hermes.h>
#else
// JSC
- #include <jsi/JSCRuntime.h>
+ #include <jsc/JSCRuntime.h>
#endif

namespace vision {
diff --git a/node_modules/react-native-vision-camera/ios/React Utils/MakeJSIRuntime.h b/node_modules/react-native-vision-camera/ios/React Utils/MakeJSIRuntime.h
index a428c01..0d80e3c 100644
--- a/node_modules/react-native-vision-camera/ios/React Utils/MakeJSIRuntime.h
+++ b/node_modules/react-native-vision-camera/ios/React Utils/MakeJSIRuntime.h
@@ -22,7 +22,7 @@
#include <v8runtime/V8RuntimeFactory.h>
#else
// JSC
- #include <jsi/JSCRuntime.h>
+ #include <React-jsc/JSCRuntime.h>
#endif

using namespace facebook;

Time to let patch-package shine! Run the following command:

npx patch-package react-native-vision-camera

Bingo! Your first patch has been successfully applied!

Step 3: Fine-Tuning Vision Camera Code Scanner

Next up is vision-camera-code-scanner. Again, create a new file and name it vision-camera-code-scanner+0.2.0.patch. Add this content:

diff --git a/node_modules/vision-camera-code-scanner/android/build.gradle b/node_modules/vision-camera-code-scanner/android/build.gradle
index b6bd964..4567cfb 100644
--- a/node_modules/vision-camera-code-scanner/android/build.gradle
+++ b/node_modules/vision-camera-code-scanner/android/build.gradle
@@ -18,11 +18,11 @@ def safeExtGet(prop, fallback) {
}

android {
- compileSdkVersion safeExtGet('VisionCameraCodeScanner_compileSdkVersion', 30)
+ compileSdkVersion safeExtGet('compileSdkVersion', 30)
ndkVersion "21.4.7075529"
defaultConfig {
- minSdkVersion safeExtGet('VisionCameraCodeScanner_minSdkVersion', 21)
- targetSdkVersion safeExtGet('VisionCameraCodeScanner_targetSdkVersion', 31)
+ minSdkVersion safeExtGet('minSdkVersion', 21)
+ targetSdkVersion safeExtGet('targetSdkVersion', 31)
versionCode 1
versionName "1.0"

@@ -56,6 +56,6 @@ dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
api project(":react-native-vision-camera")
- implementation "androidx.camera:camera-core:1.1.0-alpha06"
- implementation 'com.google.mlkit:barcode-scanning:17.0.0'
+ implementation "androidx.camera:camera-core:1.1.0-alpha08"
+ implementation 'com.google.mlkit:barcode-scanning:17.0.2'
}
diff --git a/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/BarcodeConverter.java b/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/BarcodeConverter.java
index 74e208b..eb4ed07 100644
--- a/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/BarcodeConverter.java
+++ b/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/BarcodeConverter.java
@@ -7,7 +7,7 @@ import androidx.annotation.NonNull;

import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
-import com.google.mlkit.vision.barcode.Barcode;
+import com.google.mlkit.vision.barcode.common.Barcode;

import java.util.List;

diff --git a/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/VisionCameraCodeScannerPlugin.java b/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/VisionCameraCodeScannerPlugin.java
index 8198564..a3adafd 100644
--- a/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/VisionCameraCodeScannerPlugin.java
+++ b/node_modules/vision-camera-code-scanner/android/src/main/java/com/visioncameracodescanner/VisionCameraCodeScannerPlugin.java
@@ -24,7 +24,7 @@ import androidx.camera.core.ImageProxy;
import com.google.android.gms.tasks.Tasks;
import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin;
import com.google.android.gms.tasks.Task;
-import com.google.mlkit.vision.barcode.Barcode;
+import com.google.mlkit.vision.barcode.common.Barcode;
import com.google.mlkit.vision.barcode.BarcodeScanner;
import com.google.mlkit.vision.barcode.BarcodeScanning;
import com.google.mlkit.vision.barcode.BarcodeScannerOptions;

Now, unleash patch-package once more:

npx patch-package vision-camera-code-scanner

Great job! You’ve successfully patched the second library.

Step 4: Ensuring Patch-Package Runs Post Installation

To ensure our patches remain active whenever we run the npm install or yarn install command, we'll add patch-package to the postinstall script in our package.json:

"scripts": {
"postinstall": "patch-package"
}

Step 5: Building the QR Code Reader

With the libraries set, we’re now ready to create our QR code reader. Generate a new file called QRReader.tsx and add this code:

import React, { memo, useEffect, useState } from 'react';
import { runOnJS } from 'react-native-reanimated';
import { Camera, useCameraDevices, useFrameProcessor } from 'react-native-vision-camera';
import { BarcodeFormat, scanBarcodes, Barcode } from 'vision-camera-code-scanner';
import { Container } from './styles';

interface QRReaderProps {
testID?: string;
}

const QRReader: React.FC<QRReaderProps> = ({ testID }) => {
const [hasPermission, setHasPermission] = React.useState(false);
const devices = useCameraDevices();
const device = devices.back;
const [barcodes, setBarcodes] = useState<Barcode[]>([]);

useEffect(() => {
console.log('barcodes', barcodes);
}, [barcodes]);

const frameProcessor = useFrameProcessor((frame) => {
'worklet';
const detectedBarcodes = scanBarcodes(frame, [BarcodeFormat.QR_CODE]);
runOnJS(setBarcodes)(detectedBarcodes);
}, []);

React.useEffect(() => {
(async () => {
const status = await Camera.requestCameraPermission();
setHasPermission(status === 'authorized');
})();
}, []);

return (
<Container testID={testID}>
{device && hasPermission && (
<Camera
style={{ width: '100%', height: '100%', position: 'absolute' }}
device={device}
isActive
frameProcessor={frameProcessor}
frameProcessorFps={2}
/>
)}
</Container>
);
};

export { QRReader };
export default memo(QRReader);

QRReader.defaultProps = {
testID: 'qrreader-testID',
};

This will give you a powerful QR reader that uses the back camera of your device to detect QR codes and returns its findings through console logs.

And there you have it! You’ve not only figured out how to patch your libraries in a React-Native project but also created an amazing QR code reader. But remember, patching is a temporary fix. It’s always good practice to contribute back to the open-source community by sharing your patches and improvements through a pull request. Once your changes are merged and a new version is released, you can switch to that instead of using the patch.

Here’s wishing you endless fun and success with your new QR Code Reader! Enjoy decoding!

--

--

Romario Fitzgerald

I’m a young software developer and entrepreneur who is always looking for ways to grow.