Create a mobile QR Scanner that scans via camera and image in the gallery (React Native/Expo)
In order to enhance user experience, and to make a process quick and seamless, using QR codes (Quick Response codes) is a great way to go.
QR codes have been in existence since 1994. Although originally created in the automobile industry, it has evolved into what it is today.
In this article, we would create a React Native mobile app (using Expo) that can scan a QR code via a camera or via a file in your gallery.
We are going to be building something very simple. It’s going to be a single page. The camera would fill the whole screen, while there would be a Text box and a button towards the end of the screen (the former to show the QR text; the other to pick a picture from the gallery).
Let’s begin.
Installation
To create an expo app type this in your terminal:
npx create-expo-app name-of-your-app
Let’s install the dependencies:
npx expo install expo-camera expo-image-picker expo-barcode-scanner
“Expo-camera” is to enable us to use the native camera of the phone, “expo-image-picker” is to allow us to pick an image from the image gallery, and “expo-barcode-scanner” is to scan the code.
To run the app type this in your terminal:
npx expo start
You should see something like this:
You can choose any of the options you prefer. You can scan the QR using Expo Go(for Android users) or use your camera (for iOS users). Expo Go is an app you install on your phone to see the application you are creating in real time.
My personal preference is to scan the code using my mobile phone. My advice is that you do the same, considering the fact that we are going to create an app that would need a camera to scan something.
Coding
In the root folder go to the “App.js” file. At the top import the following:
import { useState,useEffect } from 'react';
import * as ImagePicker from "expo-image-picker";
import { BarCodeScanner } from "expo-barcode-scanner";
import { Camera } from 'expo-camera';
At the top of your functional component type in the following useState(s):
const [displayText, setDisplayText]= useState("");
const [hasPermission, setHasPermission] = useState(null);
“DisplayText” would track the text to be shown, and “hasPermission” tracks if the user has granted permission for their camera to be used in this app.
When the component mounts, we would ask for permission immediately. If we don’t request permission the camera would not work for this app. The same thing would happen if the user rejects the permission.
To ask for permission type the following “UseEffect” function in the code:
useEffect(() => {
(async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === "granted");
})();
}, []);
The app should ask you for permission. Accept the permission.
In the “StyleSheet” replace the styles with this:
container: {
flex: 1,
backgroundColor: '#fff',
},
boxContainer:{
position:'absolute',
display:'flex',
justifyContent:'flex-end',
alignItems:'center',
height:'100%',
width:'100%',
zIndex:1
},
scanBoxContainer:{
position:'absolute',
alignItems: 'center',
justifyContent: 'center',
height:'100%',
width:'100%',
zIndex:0,
},
scanBox: {
width: 300,
height: 300,
borderWidth: 1,
borderColor: "white",
}
In your JSX part, replace the jsx with this:
<View style={styles.container}>
<Camera
style={{ flex: 1 }}
barCodeScannerSettings={{
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
/>
</View>
Above, in the “Camera” component, we typed in “barCodeScannerSettings” as a parameter/setting. “BarCodeScannerSettings” is used to set the type of bar code to use. You can check for more settings here, and you can check more barcode types here.
Back to the app…
The camera should show up on your phone’s screen. It should fill the entire screen.
Let’s code in the text box and button. Start with importing the “Button” from react native.
In your JSX, below the “Camera” component insert this:
<View style={styles.boxContainer}>
<View style={{marginBottom:50}}>
<Text style={{height:40, width: 300, backgroundColor:'white',marginBottom:20}}>{displayText}</Text>
<Button title='Pick from gallery'/>
</View>
</View>
<View
style={styles.scanBoxContainer}
>
<View style={styles.scanBox}></View>
</View>
Your app should look something like this:
Inside the “Camera” component insert the following:
onBarCodeScanned={(...args) => {
const data = args[0].data;
let result = JSON.stringify(data);
setDisplayText(result)
}}
Scan this QR code:
The word “Hello World” should be written in the text box. Yaaaay.
Now let’s pick an image from your phone’s gallery. First, we create a function that does that. Below useState(s) we typed earlier type in this function:
const pickImage = async () => {
// No permissions request is necessary for launching the image library
// pick an image from gallery
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false,
aspect: [4, 3],
quality: 1,
});
// if the user successfully picks an image then we check if the image has a QR code
if (result && result.assets[0].uri) {
try {
const scannedResults = await BarCodeScanner.scanFromURLAsync(
result.assets[0].uri
);
const dataNeeded = scannedResults[0].data;
setDisplayText(dataNeeded)
} catch (error) {
// if there this no QR code
setDisplayText("No QR Code Found");
setTimeout(() => setDisplayText(""), 4000);
}
}
};
In your “Button” component type this in:
onPress={pickImage}
Clicking on the button should open your file gallery. Choose an image that doesn’t have a QR code. You should see the words “No QR Code Found” displayed in the text box.
Now click on the button again and choose an image that has a QR Code. It should display the text on the code in the text box.
Yayyyyyyyyy. You have built a QR code scanning app. Well done.
I hope you liked this. Do tell me your thoughts.