barcode_scan2 Barcode & QR Scanning Guide
barcode_scan2 is a Flutter camera plugin for scanning 2D barcodes and QR codes with sound null safety support, built-in flashlight control, and customizable scanning options.
Guidelines
- Native Permission Configuration (Mandatory):
- iOS (
Info.plist): Always addNSCameraUsageDescriptionwith a user-facing explanation:<key>NSCameraUsageDescription</key> <string>Camera access is required to scan barcodes and QR codes.</string> - Android (
AndroidManifest.xml): Ensure camera permission is declared:<uses-permission android:name="android.permission.CAMERA" />
- iOS (
- Initiating Scan:
- Call
final result = await BarcodeScanner.scan(options: ...);.
- Call
- Handling Scan Results:
- Check
result.type:ResultType.Barcode: Successful scan. Accessresult.rawContentandresult.format.ResultType.Cancelled: User dismissed or backed out of the scanner. Do not treat as an error.ResultType.Error: Accessresult.rawContentfor error diagnostic information.
- Check
- Handling Permission Exceptions:
- Wrap
BarcodeScanner.scan()in atry-catchblock catchingPlatformException. - Check
if (e.code == BarcodeScanner.cameraAccessDenied)to present a permissions dialog directing the user to system settings.
- Wrap
- Format Restrictions & Performance:
- When scanning only QR codes, set
restrictFormat: [BarcodeFormat.qr]inScanOptionsto speed up recognition.
- When scanning only QR codes, set
Examples
1. Basic Barcode / QR Code Scanner
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Future<String?> scanCode(BuildContext context) async {
try {
final result = await BarcodeScanner.scan(
options: const ScanOptions(
strings: {
'cancel': 'Cancel',
'flash_on': 'Flash on',
'flash_off': 'Flash off',
},
restrictFormat: [BarcodeFormat.qr],
useCamera: -1, // Back camera default
autoEnableFlash: false,
android: AndroidOptions(
aspectTolerance: 0.5,
useAutoFocus: true,
),
),
);
switch (result.type) {
case ResultType.Barcode:
return result.rawContent;
case ResultType.Cancelled:
return null;
case ResultType.Error:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Scan error: ${result.rawContent}')),
);
return null;
}
} on PlatformException catch (e) {
if (e.code == BarcodeScanner.cameraAccessDenied) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Camera permission was denied.')),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Unexpected error: ${e.message}')),
);
}
return null;
}
}
Common Pitfalls & Anti-Patterns
- ❌ Anti-pattern: Forgetting
NSCameraUsageDescriptioninios/Runner/Info.plist, causing immediate app crash on iOS when camera opens.- ✔️ Correct: Add the description string before calling
BarcodeScanner.scan().
- ✔️ Correct: Add the description string before calling
- ❌ Anti-pattern: Assuming
result.rawContentis non-empty without checkingresult.type == ResultType.Barcode.- ✔️ Correct: Always verify
result.typefirst.
- ✔️ Correct: Always verify