React Native and Flutter barcode scanners: a practical guide
In React Native, use react-native-vision-camera's code scanner, or expo-camera's CameraView in an Expo app. In Flutter, use the mobile_scanner package. All three read QR codes and common barcodes from the live camera, and all three need a camera permission declared in your app.
Which package to use
Package APIs change between major versions. The lines below match current releases; if your installed version differs, its README is the source of truth.
- Expo app, including Expo Go: expo-camera. Barcode scanning is built into its CameraView component.
- React Native with a custom native build: react-native-vision-camera, whose useCodeScanner hook reads QR codes and barcodes.
- Flutter: mobile_scanner, which uses Google's ML Kit on Android and supports iOS, and web and macOS in recent versions.
- Avoid old tutorials built on react-native-camera, which is deprecated, and expo-barcode-scanner, which Expo deprecated in favour of expo-camera and has since removed from the SDK.
Expo QR code scanner with expo-camera
For a store build, add a camera permission message through the expo-camera config plugin in app.json, so iOS shows your reason when it asks.
- Install it with npx expo install expo-camera.
- Import the pieces: import { CameraView, useCameraPermissions } from 'expo-camera';
- In your component: const [permission, requestPermission] = useCameraPermissions();
- If permission is not granted, show a button that calls requestPermission().
- Render the camera: <CameraView style={{ flex: 1 }} facing="back" barcodeScannerSettings={{ barcodeTypes: ['qr', 'ean13', 'code128'] }} onBarcodeScanned={({ data }) => setResult(data)} />
- After a hit, set onBarcodeScanned to undefined (for example with a scanned flag in state), or it fires again on every frame the code stays in view.
React Native barcode scanner with react-native-vision-camera
VisionCamera is a full camera library with a built-in code scanner. It needs native code, so it runs in a development build rather than Expo Go.
Get the device and permission: const device = useCameraDevice('back'); and const { hasPermission, requestPermission } = useCameraPermission();
Create the scanner: const codeScanner = useCodeScanner({ codeTypes: ['qr', 'ean-13'], onCodeScanned: (codes) => console.log(codes[0]?.value) });
Render it: <Camera style={StyleSheet.absoluteFill} device={device} isActive={true} codeScanner={codeScanner} />
Set isActive to false when the screen is not focused, so the camera turns off when the user leaves. On Android the code scanner uses Google's ML Kit; the VisionCamera docs explain the Gradle setting that chooses between a bundled model and one downloaded through Google Play services.
On Android, Google also offers a ready-made code scanner screen through ML Kit, which does not need camera permission in your own app. It is Android-only, so it suits apps that only need to scan occasionally.
Flutter QR code and barcode scanner with mobile_scanner
Handle the case where rawValue is null: some barcodes contain binary data rather than text. As with the other packages, ignore repeat detections of the same value, or your navigation code will run several times.
- Add the package: flutter pub add mobile_scanner
- On iOS, add NSCameraUsageDescription to ios/Runner/Info.plist with a short reason, such as 'Used to scan QR codes'.
- Place the widget: MobileScanner(onDetect: (capture) { final value = capture.barcodes.first.rawValue; })
- For torch, camera switching or stopping and starting, create a MobileScannerController, pass it to the widget, and dispose of it with the screen.
- To scan a QR code from a photo, pass the image's file path to the controller's analyzeImage method.
Camera permissions on iOS and Android
- iOS: every app that uses the camera must set NSCameraUsageDescription. Without it the app crashes when the camera opens.
- Android: the CAMERA permission is declared in the manifest, which these packages usually add for you, and granted by the user at runtime.
- Ask at the moment the user taps Scan, with a line explaining why. A cold permission prompt on launch gets refused more often.
- If the user refuses, explain how to allow it in Settings and offer a way to pick a photo instead.
Generating QR codes and barcodes in the app
For showing a QR code in React Native or Expo, react-native-qrcode-svg is a widely used component; it draws with react-native-svg. In Flutter, qr_flutter draws QR codes, for example QrImageView(data: 'https://example.com', size: 200), and barcode_widget draws Code 128, EAN-13 and other line barcodes.
If you only need a few fixed codes, such as a link on a welcome screen, make them once with a QR code generator and bundle the SVG or PNG as an asset. There is nothing to run on the device and you can style them freely.
Testing your scanner
- Test on real devices. Simulators and emulators have limited or fake cameras.
- Try small codes, codes on screens, glossy packaging and low light.
- Check the scanner types you enabled match what users will scan. Leaving out EAN-13 is a common reason product barcodes are ignored.
- Keep a set of test codes: a web-based barcode generator and scanner are handy for making and checking samples from your desk.