https://github.com/shariaralphabyte/ultra_qr_scanner
Ultra QR Scanner ๐ฑโก pub package GitHub Platform Ultra-fast, low-latency QR code scanner plugin for Flutter with native camera preview and performance optimization.
https://github.com/shariaralphabyte/ultra_qr_scanner
flutter flutter-dependencies flutter-package flutter-plugin
Last synced: 3 months ago
JSON representation
Ultra QR Scanner ๐ฑโก pub package GitHub Platform Ultra-fast, low-latency QR code scanner plugin for Flutter with native camera preview and performance optimization.
- Host: GitHub
- URL: https://github.com/shariaralphabyte/ultra_qr_scanner
- Owner: shariaralphabyte
- License: mit
- Created: 2025-07-31T07:53:42.000Z (10 months ago)
- Default Branch: master
- Last Pushed: 2025-09-25T07:18:43.000Z (8 months ago)
- Last Synced: 2025-10-29T10:04:43.639Z (7 months ago)
- Topics: flutter, flutter-dependencies, flutter-package, flutter-plugin
- Language: Dart
- Homepage: https://pub.dev/packages/ultra_qr_scanner
- Size: 551 KB
- Stars: 1
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Ultra QR Scanner ๐ฑโก
[](https://pub.dev/packages/ultra_qr_scanner)
[](https://github.com/shariaralphabyte/ultra_qr_scanner/blob/main/LICENSE)
[](https://pub.dev/packages/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
๐ค **Auto-start scanning** - Optional automatic scanning when widget appears
๐ **Manual controls** - User-controlled start/stop with customizable UI
๐ฑ **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, buttons, 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-start Mode** | Begin scanning immediately when widget appears | Zero user interaction needed |
| **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 |
| Auto-Start Time | < 100ms | ~50ms |
| 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`:
```yaml
dependencies:
ultra_qr_scanner: ^3.0.3
```
```bash
flutter pub get
```
## ๐โโ๏ธ Quick Start
### 1. Initialize Scanner (Optional but Recommended)
```dart
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. Auto-Start Scanner (Recommended for Quick Scanning)
```dart
import 'package:ultra_qr_scanner/ultra_qr_scanner_widget.dart';
class QuickScannerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Quick QR Scanner')),
body: Container(
width: 300,
height: 300,
child: UltraQrScannerWidget(
onCodeDetected:(code , type) {
print('QR Code detected: $qrCode');
Navigator.pop(context, qrCode);
},
showFlashToggle: true, // Show flash button
autoStop: true, // Auto-stop after detection
showStartStopButton: false, // Hide manual controls
autoStart: true, // Start scanning immediately
),
),
);
}
}
```
### 3. Manual Scanner (Traditional User-Controlled)
```dart
class ManualScannerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Manual QR Scanner')),
body: Container(
width: 300,
height: 300,
child: UltraQrScannerWidget(
onCodeDetected:(code , type) {
print('QR Code detected: $qrCode');
Navigator.pop(context, qrCode);
},
showFlashToggle: true, // Show flash button
autoStop: true, // Auto-stop after detection
showStartStopButton: true, // Show start/stop button
autoStart: false, // Wait for user to start
),
),
);
}
}
```
### 4. Programmatic Scanning (Alternative)
```dart
// Single scan
Future 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? _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
### Scanning Modes
The widget supports two main scanning modes:
#### ๐ค **Auto-Start Mode** (Instant Scanning)
Perfect for quick scanning scenarios where you want immediate results:
```dart
UltraQrScannerWidget(
onCodeDetected:(code , type) => handleQRCode(qrCode),
autoStart: true, // Start scanning immediately
showStartStopButton: false, // Hide manual controls
autoStop: true, // Stop after first detection
showFlashToggle: true, // Optional flash control
)
```
#### ๐ **Manual Mode** (User-Controlled)
Traditional scanning with user controls:
```dart
UltraQrScannerWidget(
onCodeDetected:(code , type) => handleQRCode(qrCode),
autoStart: false, // Wait for user action
showStartStopButton: true, // Show start/stop button
autoStop: true, // Stop after first detection
showFlashToggle: true, // Optional flash control
)
```
#### ๐ **Hybrid Mode** (Best of Both)
Auto-start with manual controls available:
```dart
UltraQrScannerWidget(
onCodeDetected:(code , type) => handleQRCode(qrCode),
autoStart: true, // Start immediately
showStartStopButton: true, // But also show controls
autoStop: false, // Continuous scanning
showFlashToggle: true, // Flash control
)
```
### Widget Configuration Options
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `onQrDetected` | `Function(String)` | **Required** | Callback when QR code is detected |
| `autoStart` | `bool` | `false` | Start scanning automatically when widget appears |
| `showStartStopButton` | `bool` | `true` | Show/hide the start/stop scan button |
| `autoStop` | `bool` | `true` | Stop scanning after first QR code detection |
| `showFlashToggle` | `bool` | `false` | Show/hide flash/torch toggle button |
| `overlay` | `Widget?` | `null` | Custom overlay widget (uses default if null) |
### Custom Overlay Example
```dart
UltraQrScannerWidget(
onCodeDetected:(code , type) (qrCode) => handleQRCode(qrCode),
autoStart: true,
showStartStopButton: false,
overlay: Stack(
children: [
// Semi-transparent background
Container(color: Colors.black54),
// Custom scanning frame
Center(
child: Container(
width: 250,
height: 250,
decoration: BoxDecoration(
border: Border.all(color: Colors.green, width: 4),
borderRadius: BorderRadius.circular(20),
),
child: Stack(
children: [
// Corner decorations
...buildCornerDecorations(),
// Center dot
Center(
child: Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
),
),
),
],
),
),
),
// Custom instructions
Positioned(
top: 60,
left: 0,
right: 0,
child: Column(
children: [
Icon(Icons.qr_code_scanner, color: Colors.white, size: 48),
SizedBox(height: 16),
Text(
'Scan QR Code',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'Position the QR code within the frame',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white70,
fontSize: 16,
),
),
],
),
),
],
),
)
```
### Usage Scenarios
#### ๐ **Instant QR Scanner (No UI Friction)**
```dart
// Perfect for: Payment apps, quick actions, URL scanning
UltraQrScannerWidget(
onCodeDetected:(code , type) => processPayment(code),
autoStart: true,
showStartStopButton: false,
autoStop: true,
)
```
#### ๐ท **Traditional Scanner (User Control)**
```dart
// Perfect for: Document scanning, batch operations, careful scanning
UltraQrScannerWidget(
onCodeDetected:(code , type) => addToList(code),
autoStart: false,
showStartStopButton: true,
autoStop: false, // Continuous scanning
)
```
#### ๐ **Full-Featured Scanner**
```dart
// Perfect for: Professional apps, feature-rich scanning
UltraQrScannerWidget(
oonCodeDetected:(code , type) => handleCode(code),
autoStart: true,
showStartStopButton: true,
showFlashToggle: true,
autoStop: true,
)
```
## ๐ง Advanced Features
### Flash Control
```dart
// Toggle flashlight
await UltraQrScanner.toggleFlash(true); // Turn on
await UltraQrScanner.toggleFlash(false); // Turn off
```
### Camera Switching
```dart
// Switch between front and back camera
await UltraQrScanner.switchCamera('front'); // Use front camera
await UltraQrScanner.switchCamera('back'); // Use back camera
```
### Scanner Lifecycle Management
```dart
// 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`:
```xml
```
Add to `android/app/build.gradle`:
```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`:
```xml
NSCameraUsageDescription
Camera access is required to scan QR codes
```
Ensure minimum iOS version 11.0+ in `ios/Podfile`:
```ruby
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
```dart
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 {
String? lastQRCode;
bool useAutoMode = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Ultra QR Scanner'),
centerTitle: true,
actions: [
IconButton(
icon: Icon(useAutoMode ? Icons.auto_awesome : Icons.touch_app),
onPressed: () {
setState(() {
useAutoMode = !useAutoMode;
});
},
tooltip: useAutoMode ? 'Switch to Manual' : 'Switch to Auto',
),
],
),
body: Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Mode indicator
Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: useAutoMode ? Colors.green.shade100 : Colors.blue.shade100,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: useAutoMode ? Colors.green : Colors.blue,
width: 2,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
useAutoMode ? Icons.flash_auto : Icons.touch_app,
color: useAutoMode ? Colors.green.shade700 : Colors.blue.shade700,
size: 20,
),
SizedBox(width: 8),
Text(
useAutoMode ? '๐ AUTO MODE' : '๐ MANUAL MODE',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: useAutoMode ? Colors.green.shade700 : Colors.blue.shade700,
),
),
],
),
),
SizedBox(height: 10),
Text(
useAutoMode
? 'Scanning starts automatically when camera opens'
: 'Tap the Start Scan button to begin scanning',
style: TextStyle(fontSize: 16),
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(
onCodeDetected:(code , type) {
setState(() {
lastQRCode = code;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Scanned: $code'),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
duration: Duration(seconds: 2),
),
);
},
showFlashToggle: true,
autoStop: true,
// Dynamic mode switching
autoStart: useAutoMode,
showStartStopButton: !useAutoMode,
),
),
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: 20),
// Mode comparison
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'๐ก Scanning Modes:',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 8),
Text('๐ Auto Mode: Instant scanning, no buttons needed'),
Text('๐ Manual Mode: User-controlled start/stop'),
Text('โก Both modes: Auto-stop after detection'),
Text('๐ฆ Flash control available in both modes'),
Text('๐ท Camera switching available in both modes'),
],
),
),
],
),
),
),
);
}
}
```
## ๐ Error Handling
```dart
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;
case 'NOT_PREPARED':
// Scanner needs initialization
break;
default:
print('Scanner error: ${e.message}');
}
} catch (e) {
// Handle other errors
print('General error: $e');
}
```
## ๐ Performance Tips
### 1. **Choose the Right Mode for Your Use Case**
```dart
// โ
GOOD: Auto-mode for quick actions (payments, URLs)
UltraQrScannerWidget(
autoStart: true,
showStartStopButton: false,
autoStop: true,
)
// โ
GOOD: Manual mode for careful scanning (documents, batch)
UltraQrScannerWidget(
autoStart: false,
showStartStopButton: true,
autoStop: false,
)
```
### 2. **Initialize Early (Optional but Recommended)**
```dart
// โ
GOOD: Initialize during app startup for faster access
void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (await UltraQrScanner.requestPermissions()) {
await UltraQrScanner.prepareScanner();
}
runApp(MyApp());
}
```
### 3. **Use Widget for Better Performance**
```dart
// โ
RECOMMENDED: Use UltraQrScannerWidget
UltraQrScannerWidget(
onQrDetected: (code) => handleCode(code),
autoStart: true,
)
// โ ALTERNATIVE: Programmatic scanning (requires more setup)
final result = await UltraQrScanner.scanOnce();
```
## ๐ 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 in Auto Mode**
- Updated in v2.1.0 with better initialization timing
- Ensure proper widget constraints (width/height)
- Check console for platform view creation logs
**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
- Try manual mode if auto-mode has issues
**4. Controls Not Responding**
- Verify widget configuration parameters
- Check if scanner is properly initialized
- Ensure proper error handling in callbacks
### 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
### [3.0.3] - Latest
- ๐ค **Auto-start scanning mode** - Begin scanning immediately when widget appears
- ๐ค **Support Google 16KB Page size** - Support Google 16KB Page size
- ๐ **Enhanced manual controls** - Better user-controlled scanning experience
- ๐๏ธ **Flexible UI options** - Show/hide start/stop button independently
- โฑ๏ธ **Improved initialization** - Better timing for auto-start mode
- ๐ง **Better error handling** - More robust initialization and state management
- ๐ฑ **Enhanced examples** - Complete auto/manual mode demonstrations
### [2.0.0] - Previous Major Release
- ๐ **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
## ๐ค Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
### Development Setup
```bash
git clone https://github.com/shariaralphabyte/ultra_qr_scanner.git
cd ultra_qr_scanner
flutter pub get
cd example
flutter run
```
### Running Tests
```bash
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](LICENSE) file for details.
## ๐ Acknowledgments
- [MLKit Barcode Scanning](https://developers.google.com/ml-kit/vision/barcode-scanning) for Android QR detection
- [Vision Framework](https://developer.apple.com/documentation/vision) for iOS QR detection
- [CameraX](https://developer.android.com/camerax) for Android camera handling
- [AVFoundation](https://developer.apple.com/av-foundation/) for iOS camera management
- Flutter team for platform views and native integration
## ๐ Support
- ๐ [Documentation](https://pub.dev/documentation/ultra_qr_scanner/latest/)
- ๐ [Issue Tracker](https://github.com/shariaralphabyte/ultra_qr_scanner/issues)
- ๐ฌ [Discussions](https://github.com/shariaralphabyte/ultra_qr_scanner/discussions)
- ๐ง Email: contact.shariar.cse@gmail.com
---