ultra_qr_scanner 2.0.2
ultra_qr_scanner: ^2.0.2 copied to clipboard
Ultra-fast, low-latency QR code scanner plugin for Flutter with native performance optimization.
Ultra QR Scanner ๐ฑโก #
Ultra-fast, low-latency QR code scanner plugin for Flutter with native camera preview and performance optimization.
๐ฏ Goal: Open scanner โ show camera preview โ detect QR instantly โ return result โ done โ
โจ Features #
๐ Ultra-fast startup - Preload scanner during app initialization for instant access
โก Native performance - CameraX (Android) + AVCapture (iOS) with platform views
๐ธ Live camera preview - Real-time camera feed with customizable overlay
๐ฑ Simple API - Single scan or continuous stream modes
๐ฆ Flash control - Toggle flashlight on supported devices
๐ท Camera switching - Front/back camera support
๐ก๏ธ Production ready - Comprehensive error handling & memory management
๐จ Customizable UI - Custom overlays and scanning frames
๐ Performance Optimizations #
| Feature | Description | Benefit |
|---|---|---|
| Native Camera APIs | CameraX on Android, AVCaptureSession on iOS | Maximum hardware utilization |
| Platform Views | Native camera preview rendering | Seamless integration with Flutter UI |
| ML Frameworks | MLKit Barcode Scanning (Android), Vision API (iOS) | Optimized QR detection |
| Threading | Background processing with main thread UI updates | Non-blocking UI performance |
| Auto-stop | Immediate camera shutdown after detection | Zero waste of resources |
| Preloading | Initialize during app startup | < 50ms to first scan |
| Memory Management | Proper cleanup and lifecycle handling | Leak-free operation |
๐ Benchmarks #
| Metric | Target | Typical Result |
|---|---|---|
| Cold Start Time | < 300ms | ~200ms |
| QR Detection Speed | < 100ms | ~50ms |
| Memory Usage | < 50MB | ~35MB |
| Battery Impact | Minimal | 2-3% per hour |
| Frame Rate | 30 FPS | Stable 30 FPS |
๐ Installation #
Add to your pubspec.yaml:
dependencies:
ultra_qr_scanner: ^2.0.2
flutter pub get
๐โโ๏ธ Quick Start #
1. Initialize Scanner (Optional but Recommended) #
import 'package:ultra_qr_scanner/ultra_qr_scanner.dart';
// Best practice: Initialize during app startup for faster access
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Request camera permission and prepare scanner
final hasPermission = await UltraQrScanner.requestPermissions();
if (hasPermission) {
await UltraQrScanner.prepareScanner();
}
runApp(MyApp());
}
2. Using the Scanner Widget (Recommended) #
import 'package:ultra_qr_scanner/ultra_qr_scanner_widget.dart';
class QRScannerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('QR Scanner')),
body: Container(
width: 300,
height: 300,
child: UltraQrScannerWidget(
onQrDetected: (qrCode) {
print('QR Code detected: $qrCode');
Navigator.pop(context, qrCode);
},
showFlashToggle: true, // Show flash button
autoStop: true, // Auto-stop after detection
),
),
);
}
}
3. Programmatic Scanning (Alternative) #
// Single scan
Future<void> scanQRCode() async {
try {
final qrCode = await UltraQrScanner.scanOnce();
if (qrCode != null) {
print('Scanned QR Code: $qrCode');
}
} catch (e) {
print('Scan failed: $e');
}
}
// Continuous scanning stream
StreamSubscription<String>? _scanSubscription;
void startContinuousScanning() {
_scanSubscription = UltraQrScanner.scanStream().listen(
(qrCode) {
print('Detected QR Code: $qrCode');
},
onError: (error) {
print('Scan error: $error');
},
);
}
void stopScanning() {
_scanSubscription?.cancel();
UltraQrScanner.stopScanner();
}
๐จ Widget Customization #
Basic Widget Configuration #
UltraQrScannerWidget(
onQrDetected: (qrCode) => handleQRCode(qrCode),
showFlashToggle: true, // Show/hide flash toggle button
autoStop: true, // Stop scanning after first detection
overlay: null, // Use default overlay or provide custom
)
Custom Overlay Example #
UltraQrScannerWidget(
onQrDetected: (qrCode) => handleQRCode(qrCode),
overlay: Stack(
children: [
// Semi-transparent background
Container(color: Colors.black54),
// Scanning frame
Center(
child: Container(
width: 250,
height: 250,
decoration: BoxDecoration(
border: Border.all(color: Colors.green, width: 3),
borderRadius: BorderRadius.circular(16),
),
),
),
// Instructions
Positioned(
top: 50,
left: 0,
right: 0,
child: Text(
'Position QR code within the frame',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
],
),
)
Full-Screen Scanner Example #
class FullScreenScannerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('QR Scanner'),
backgroundColor: Colors.transparent,
elevation: 0,
),
extendBodyBehindAppBar: true,
body: UltraQrScannerWidget(
onQrDetected: (qrCode) {
Navigator.pop(context, qrCode);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Scanned: $qrCode'),
backgroundColor: Colors.green,
),
);
},
showFlashToggle: true,
autoStop: true,
),
);
}
}
๐ง Advanced Features #
Flash Control #
// Toggle flashlight
await UltraQrScanner.toggleFlash(true); // Turn on
await UltraQrScanner.toggleFlash(false); // Turn off
Camera Switching #
// Switch between front and back camera
await UltraQrScanner.switchCamera('front'); // Use front camera
await UltraQrScanner.switchCamera('back'); // Use back camera
Scanner Lifecycle Management #
// Check if scanner is ready
if (UltraQrScanner.isPrepared) {
// Ready to scan
} else {
// Need to prepare first
await UltraQrScanner.prepareScanner();
}
// Manually stop scanner
await UltraQrScanner.stopScanner();
๐ Permissions Setup #
Android #
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Add to android/app/build.gradle:
dependencies {
implementation 'androidx.camera:camera-camera2:1.2.3'
implementation 'androidx.camera:camera-lifecycle:1.2.3'
implementation 'androidx.camera:camera-view:1.2.3'
implementation 'com.google.mlkit:barcode-scanning:17.2.0'
}
iOS #
Add to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required to scan QR codes</string>
Ensure minimum iOS version 11.0+ in ios/Podfile:
platform :ios, '11.0'
๐ฑ Platform Support #
| Platform | Camera API | ML Framework | Preview | Min Version | Status |
|---|---|---|---|---|---|
| Android | CameraX + PreviewView | MLKit Barcode | โ Native | API 21 (Android 5.0) | โ Fully Supported |
| iOS | AVCapture + PreviewLayer | Vision Framework | โ Native | iOS 11.0+ | โ Fully Supported |
๐ฏ Complete Example App #
import 'package:flutter/material.dart';
import 'package:ultra_qr_scanner/ultra_qr_scanner.dart';
import 'package:ultra_qr_scanner/ultra_qr_scanner_widget.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Ultra QR Scanner Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String? lastQRCode;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Ultra QR Scanner'),
centerTitle: true,
),
body: Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Scan QR code to see results below',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
// Scanner Widget
Container(
width: 300,
height: 300,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: UltraQrScannerWidget(
onQrDetected: (code) {
setState(() {
lastQRCode = code;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Scanned: $code'),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
);
},
showFlashToggle: true,
autoStop: true,
),
),
SizedBox(height: 20),
// Results Display
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.shade300),
),
child: Column(
children: [
Text(
'Last Scanned Code:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.grey.shade700,
),
),
SizedBox(height: 8),
Text(
lastQRCode ?? 'No QR code scanned yet',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
],
),
),
SizedBox(height: 30),
// Feature highlights
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'โก Features:',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 8),
Text('โ
Live camera preview'),
Text('โ
Ultra-fast QR detection'),
Text('โ
Flash/torch support'),
Text('โ
Front/back camera switching'),
Text('โ
Custom overlay support'),
Text('โ
Auto-stop functionality'),
Text('โ
Memory leak prevention'),
],
),
),
],
),
),
),
);
}
}
๐ Error Handling #
try {
await UltraQrScanner.prepareScanner();
final result = await UltraQrScanner.scanOnce();
// Handle success
} on UltraQrScannerException catch (e) {
// Handle scanner-specific errors
switch (e.code) {
case 'PERMISSION_DENIED':
// Show permission dialog
break;
case 'NO_CAMERA':
// Handle no camera available
break;
default:
print('Scanner error: ${e.message}');
}
} catch (e) {
// Handle other errors
print('General error: $e');
}
๐ Performance Tips #
1. Initialize Early (Optional but Recommended) #
// โ
GOOD: Initialize during app startup for faster access
void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (await UltraQrScanner.requestPermissions()) {
await UltraQrScanner.prepareScanner();
}
runApp(MyApp());
}
2. Use Widget for Better Performance #
// โ
RECOMMENDED: Use UltraQrScannerWidget
UltraQrScannerWidget(
onQrDetected: (code) => handleCode(code),
showFlashToggle: true,
)
// โ ALTERNATIVE: Programmatic scanning (requires more setup)
final result = await UltraQrScanner.scanOnce();
3. Proper Cleanup #
// Widget handles cleanup automatically, but for programmatic use:
@override
void dispose() {
UltraQrScanner.stopScanner();
super.dispose();
}
๐ Troubleshooting #
Common Issues #
1. Camera Permission Denied
- Ensure permissions are added to AndroidManifest.xml (Android) and Info.plist (iOS)
- Request permissions before using scanner
- Test on physical device (camera not available in simulators)
2. Black Screen / No Camera Preview
- Verify platform view is properly set up
- Check if camera permissions are granted
- Ensure proper widget constraints (width/height)
3. QR Codes Not Detected
- Ensure good lighting conditions
- Check if QR code is clearly visible and not damaged
- Verify QR code format is supported
4. Memory Leaks
- Always dispose of scan subscriptions
- Use the widget instead of programmatic scanning when possible
- The widget handles lifecycle automatically
Platform-Specific Issues #
Android:
- Minimum SDK version 21+ required
- Add camera dependencies to build.gradle
- Test on multiple device orientations
iOS:
- Minimum iOS 11.0+ required
- Test on physical device only (simulator has no camera)
- Ensure proper Info.plist configuration
๐ What's New #
[2.0.0] - Latest #
- ๐ Live camera preview with native platform views
- ๐ธ Camera switching between front/back cameras
- ๐ฆ Flash/torch control for better scanning in low light
- ๐จ Customizable overlays and scanning frames
- ๐งน Improved memory management and lifecycle handling
- ๐ Better performance with native camera integration
- ๐ ๏ธ Enhanced error handling with specific error codes
- ๐ฑ Better widget architecture with proper constraints
[1.x.x] - Previous #
- โก Ultra-fast QR code scanning
- ๐ฑ Basic scanning functionality
- ๐ก๏ธ Error handling and permissions
๐ค Contributing #
We welcome contributions! Please see our Contributing Guide for details.
Development Setup #
git clone https://github.com/shariaralphabyte/ultra_qr_scanner.git
cd ultra_qr_scanner
flutter pub get
cd example
flutter run
Running Tests #
flutter test # Unit tests
flutter drive --target=test_driver/app.dart # Integration tests
๐ License #
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments #
- MLKit Barcode Scanning for Android QR detection
- Vision Framework for iOS QR detection
- CameraX for Android camera handling
- AVFoundation for iOS camera management
- Flutter team for platform views and native integration
๐ Support #
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
- ๐ง Email: [email protected]