A QR code & Barcode Scanner for React Native Projects.
For React Native developers that need to scan barcodes and QR codes in their apps, this package is a useful resource. It supports React Native's new Fabric Native architecture and was created in Kotlin (Android) and Swift (iOS) with Objective-C++ bridges.
With this package, users can quickly and easily scan barcodes and QR codes with their device's camera. Using this package, several types of codes can be scanned, and it is simple to use and integrate into your existing projects.
If you want to provide your React Native app the ability to read barcodes and QR codes, you should definitely give this package some thought.
The @pushpendersingh/react-native-scanner
package also includes a flashlight feature that can be turned on and off. This can be useful when scanning QR codes & barcodes in low light conditions.
- π± Cross-platform - Works on both iOS and Android
- π New Architecture Ready - Built with Turbo Modules & Fabric
- π· Camera Preview - Real-time camera feed with preview
- π Multiple Formats - Supports 13+ barcode formats (QR, EAN, Code128, etc.)
- β‘ High Performance - Optimized with CameraX (Android) & AVFoundation (iOS)
- π― Easy Integration - Simple API with event-based scanning
- π‘ Flash Support - Toggle flashlight on/off
- π Lifecycle Management - Automatic camera resource handling
- π¨ Customizable - Flexible styling options
npm install @pushpendersingh/react-native-scanner
or
yarn add @pushpendersingh/react-native-scanner
- Install CocoaPods dependencies:
cd ios && pod install && cd ..
- Add camera permission to
Info.plist
:
<key>NSCameraUsageDescription</key>
<string>We need camera access to scan barcodes</string>
Add camera permission to AndroidManifest.xml
:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
import React, { useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { BarcodeScanner, CameraView } from '@pushpendersingh/react-native-scanner';
export default function App() {
const [scanning, setScanning] = useState(false);
const [result, setResult] = useState('');
const startScanning = async () => {
try {
setScanning(true);
await BarcodeScanner.startScanning((barcode) => {
console.log('Barcode detected:', barcode);
setResult(`${barcode.type}: ${barcode.data}`);
stopScanning();
});
} catch (error) {
console.error('Failed to start scanning:', error);
}
};
const stopScanning = async () => {
try {
await BarcodeScanner.stopScanning();
setScanning(false);
} catch (error) {
console.error('Failed to stop scanning:', error);
}
};
return (
<View style={styles.container}>
<CameraView style={styles.camera} />
<View style={styles.controls}>
<TouchableOpacity
style={styles.button}
onPress={scanning ? stopScanning : startScanning}
>
<Text style={styles.buttonText}>
{scanning ? 'Stop Scanning' : 'Start Scanning'}
</Text>
</TouchableOpacity>
{result && (
<View style={styles.resultContainer}>
<Text style={styles.resultText}>{result}</Text>
</View>
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
camera: {
flex: 1,
},
controls: {
position: 'absolute',
bottom: 50,
left: 0,
right: 0,
alignItems: 'center',
},
button: {
backgroundColor: '#007AFF',
paddingHorizontal: 32,
paddingVertical: 16,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
resultContainer: {
marginTop: 16,
backgroundColor: 'rgba(0,0,0,0.7)',
padding: 16,
borderRadius: 8,
},
resultText: {
color: 'white',
fontSize: 14,
},
});
Starts the barcode scanning process.
BarcodeScanner.startScanning((barcode: BarcodeResult) => {
console.log('Type:', barcode.type);
console.log('Data:', barcode.data);
console.log('Raw:', barcode.raw);
});
Parameters:
callback: (barcode: BarcodeResult) => void
- Called when a barcode is detected
Returns: Promise<void>
Stops the barcode scanning process.
await BarcodeScanner.stopScanning();
Returns: Promise<void>
Releases the camera resources completely.
await BarcodeScanner.releaseCamera();
Returns: Promise<void>
Toggles the camera flash on/off.
await BarcodeScanner.setFlash(true); // Turn on
await BarcodeScanner.setFlash(false); // Turn off
Parameters:
enabled: boolean
- Enable or disable flash
Returns: Promise<void>
Checks if camera permission is currently granted.
const hasPermission = await BarcodeScanner.hasCameraPermission();
console.log('Camera permission granted:', hasPermission);
Returns: Promise<boolean>
- true
if permission granted, false
otherwise
Requests camera permission from the user with native promise resolution.
const granted = await BarcodeScanner.requestCameraPermission();
if (granted) {
console.log('Permission granted!');
// Start scanning
} else {
console.log('Permission denied');
// Show error or guide user to settings
}
Returns: Promise<boolean>
- true
if user grants permission, false
if denied
Platform Support:
- β iOS: Fully supported with native callback
- β Android: Fully supported with native callback (API 23+)
Note: This method shows the native system permission dialog and waits for the user's response, then resolves the promise based on their choice.
React component that renders the camera preview.
<CameraView style={{ flex: 1 }} />
Props:
style?: ViewStyle
- Style for the camera view container
interface BarcodeResult {
type: string; // Barcode format (e.g., 'QR_CODE', 'EAN_13')
data: string; // Decoded barcode data
raw: string; // Raw barcode value
}
import { BarcodeScanner } from '@pushpendersingh/react-native-scanner';
const [flashEnabled, setFlashEnabled] = useState(false);
const toggleFlash = async () => {
const newState = !flashEnabled;
await BarcodeScanner.setFlash(newState);
setFlashEnabled(newState);
};
import { useEffect } from 'react';
import { BarcodeScanner } from '@pushpendersingh/react-native-scanner';
useEffect(() => {
// Start scanning on mount
BarcodeScanner.startScanning(handleBarcode);
// Cleanup on unmount
return () => {
BarcodeScanner.stopScanning();
BarcodeScanner.releaseCamera();
};
}, []);
The library now provides built-in native camera permission methods that work seamlessly on both iOS and Android with proper promise resolution based on user response.
The library includes native methods that handle camera permissions with proper callbacks:
import React, { useEffect, useState } from 'react';
import { View, Text, Button, Alert } from 'react-native';
import { BarcodeScanner, CameraView } from '@pushpendersingh/react-native-scanner';
export default function App() {
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [scanning, setScanning] = useState(false);
useEffect(() => {
checkPermission();
}, []);
const checkPermission = async () => {
const granted = await BarcodeScanner.hasCameraPermission();
setHasPermission(granted);
};
const requestPermission = async () => {
const granted = await BarcodeScanner.requestCameraPermission();
setHasPermission(granted);
if (granted) {
Alert.alert('Success', 'Camera permission granted!');
} else {
Alert.alert(
'Permission Denied',
'Camera permission is required to scan barcodes'
);
}
};
const startScanning = async () => {
// Check permission before scanning
const granted = await BarcodeScanner.hasCameraPermission();
if (!granted) {
Alert.alert(
'Permission Required',
'Please grant camera permission to scan barcodes',
[{ text: 'Grant Permission', onPress: requestPermission }]
);
return;
}
setScanning(true);
await BarcodeScanner.startScanning((barcode) => {
console.log('Scanned:', barcode);
BarcodeScanner.stopScanning();
setScanning(false);
});
};
if (hasPermission === null) {
return <Text>Checking camera permission...</Text>;
}
if (hasPermission === false) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ marginBottom: 20 }}>Camera permission not granted</Text>
<Button title="Grant Permission" onPress={requestPermission} />
</View>
);
}
return (
<View style={{ flex: 1 }}>
<CameraView style={{ flex: 1 }} />
<Button
title={scanning ? 'Stop Scanning' : 'Start Scanning'}
onPress={startScanning}
/>
</View>
);
}
Key Features:
- β Cross-platform: Works on both iOS (API 10+) and Android (API 23+)
- β
Promise-based: Returns
true
when granted,false
when denied - β Native callbacks: Waits for actual user response from system dialog
- β No dependencies: No need for additional permission libraries
For more advanced permission handling (checking settings, handling blocked state, etc.), you can use react-native-permissions
:
npm install react-native-permissions
# or
yarn add react-native-permissions
import { request, check, PERMISSIONS, RESULTS } from 'react-native-permissions';
import { Platform, Linking } from 'react-native';
const checkCameraPermission = async () => {
const permission = Platform.select({
ios: PERMISSIONS.IOS.CAMERA,
android: PERMISSIONS.ANDROID.CAMERA,
});
const result = await check(permission);
switch (result) {
case RESULTS.GRANTED:
return 'granted';
case RESULTS.DENIED:
return 'denied';
case RESULTS.BLOCKED:
return 'blocked';
default:
return 'unavailable';
}
};
const requestCameraPermission = async () => {
const permission = Platform.select({
ios: PERMISSIONS.IOS.CAMERA,
android: PERMISSIONS.ANDROID.CAMERA,
});
const result = await request(permission);
if (result === RESULTS.BLOCKED) {
// User has blocked permission, guide them to settings
Alert.alert(
'Permission Blocked',
'Please enable camera permission in settings',
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'Open Settings', onPress: () => Linking.openSettings() },
]
);
return false;
}
return result === RESULTS.GRANTED;
};
This library supports a wide range of barcode formats across different categories:
1D Product | 1D Industrial | 2D |
---|---|---|
UPC-A | Code 39 | QR Code |
UPC-E | Code 93 | Data Matrix |
EAN-8 | Code 128 | Aztec |
EAN-13 | Codabar | PDF 417 |
ITF |
Format Details:
- 1D Product Codes: Commonly used in retail (UPC-A, UPC-E, EAN-8, EAN-13)
- 1D Industrial Codes: Used in logistics and inventory (Code 39, Code 93, Code 128, Codabar, ITF)
- 2D Codes: High-density codes for storing more data (QR Code, Data Matrix, Aztec, PDF 417)
Total Supported Formats: 13 barcode types
- CameraX 1.5.0 - Modern camera API with lifecycle awareness
- ML Kit Barcode Scanning 17.3.0 - Google's ML-powered barcode detection
- Kotlin - Native implementation
- AVFoundation - Native camera framework
- Vision Framework - Apple's barcode detection
- Swift 5.0 - Native implementation
- New Architecture - Turbo Modules + Fabric support
- React Native 0.81+ - Minimum version requirement
iOS:
- Check camera permission in
Info.plist
- Ensure you're running on a physical device (simulator doesn't have camera)
Android:
- Check camera permission in
AndroidManifest.xml
- Verify Google Play Services is installed
- Ensure good lighting conditions
- Hold barcode steady and at proper distance
- Check that barcode format is supported
- Verify barcode is not damaged or distorted
β Fixed: Previously, the scanner could detect EID and MEID but had issues scanning IMEI and IMEI2 numbers. This has been resolved in the current version.
How it works:
- IMEI and IMEI2 are typically encoded as CODE_128 or CODE_39 barcodes
- The scanner now properly detects and decodes these formats
- Both IMEI (15 digits) and IMEI2 (dual SIM devices) are fully supported
Tips for scanning IMEI:
- Ensure the IMEI barcode is clean and undamaged
- Use good lighting (enable flashlight if needed)
- Hold device steady at 10-15cm distance from the barcode
- IMEI barcodes are usually found on device packaging or SIM trays
iOS:
cd ios && pod deintegrate && pod install && cd ..
Android:
cd android && ./gradlew clean && cd ..
Check out the example app for a complete working implementation.
Run the example:
# Install dependencies
cd example && yarn
# iOS
cd example && npx pod-install && yarn ios
# Android
cd example && yarn android
We're constantly working to improve this library. Here are some planned enhancements:
- Enhanced Permission Handling - β
Implemented proper native permission callback mechanism for
requestCameraPermission()
method with promise resolution based on user response (iOS & Android API 23+)
- Barcode Generation - Add ability to generate barcodes/QR codes
- Image Analysis - Support scanning barcodes from gallery images
- Advanced Camera Controls - Zoom, focus, and exposure controls
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature
- Make your changes
- Run tests:
yarn test
- Commit:
git commit -m 'Add new feature'
- Push:
git push origin feature/my-feature
- Open a Pull Request
Please read our Code of Conduct before contributing.
MIT Β© Pushpender Singh
- Built with create-react-native-library
- Uses CameraX on Android
- Uses AVFoundation on iOS
- Barcode detection powered by ML Kit (Android) and Vision (iOS)
- π Report a bug
- π‘ Request a feature
If you find this package helpful, please give it a βοΈ on GitHub!