qr_scanner_hybrid 0.1.0+1
qr_scanner_hybrid: ^0.1.0+1 copied to clipboard
High-accuracy QR code scanner using dual scanning engines (Google ML Kit + ZXing) for maximum reliability in various lighting conditions.
QR Scanner Hybrid #
A high-accuracy QR code scanner for Flutter that combines Google ML Kit and ZXing scanning engines for maximum reliability across different lighting conditions and QR code qualities.
Features #
- Dual Scanning Engines: Combines Google ML Kit (real-time) and ZXing (enhanced processing) for superior accuracy
- Automatic Fallback: Switches to ZXing enhancement when ML Kit struggles with difficult codes
- Built-in Torch: Toggle flashlight for low-light scanning
- Performance Optimized: Frame throttling and intelligent processing to minimize battery drain
- Image Enhancement: Automatic contrast and grayscale adjustments for challenging QR codes
- Cross-Platform: Works on Android and iOS
- Easy Integration: Single widget drop-in solution
Screenshots #
| Scanning | Detected |
|---|---|
![]() |
![]() |
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
qr_scanner_hybrid: ^0.1.0
Then run:
flutter pub get
Platform Setup #
Android
Add the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Update android/app/build.gradle:
android {
compileSdkVersion 34 // or higher
defaultConfig {
minSdkVersion 21 // ML Kit requires API 21+
}
}
iOS
Add the following to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required to scan QR codes</string>
Update minimum iOS version in ios/Podfile:
platform :ios, '12.0' # or higher
Usage #
Basic Implementation #
import 'package:flutter/material.dart';
import 'package:qr_scanner_hybrid/qr_scanner_hybrid.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const QrScannerHybrid(),
);
}
}
With Callback and Auto-Close #
import 'package:flutter/material.dart';
import 'package:qr_scanner_hybrid/qr_scanner_hybrid.dart';
class ScannerPage extends StatelessWidget {
const ScannerPage({super.key});
void _scanQrCode(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QrScannerHybrid(
autoClose: true,
onDetected: (data, engine) {
print('QR Code detected via $engine: $data');
},
),
),
);
if (result != null && result is Map<String, String>) {
// Handle the scanned result
String qrData = result['data']!;
String engine = result['engine']!;
print('Scanned: $qrData');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('QR Scanner')),
body: Center(
child: ElevatedButton(
onPressed: () => _scanQrCode(context),
child: const Text('Scan QR Code'),
),
),
);
}
}
With Custom UI Configuration #
QrScannerHybrid(
onDetected: (data, engine) {
print('Detected: $data via $engine');
},
config: const ScannerConfig(
title: 'Scan QR Code',
borderColor: Colors.blue,
borderWidth: 4,
borderRadius: 20,
scanAreaSize: 0.7,
appBarColor: Colors.blue,
overlayColor: Colors.black54,
showStatusText: true,
showTorchToggle: true,
),
)
Minimal Configuration #
QrScannerHybrid(
autoClose: true,
config: const ScannerConfig(
showAppBar: false,
showStatusText: false,
scanAreaSize: 0.8,
),
)
How It Works #
- Primary Scanning: ML Kit processes camera frames in real-time (~8 fps) for instant detection
- Smart Fallback: After 15 frames without detection, triggers enhanced ZXing scan
- Image Enhancement: Captures photo, applies grayscale + contrast boost using isolate
- ZXing Processing: Enhanced image processed with
tryHardermode for difficult codes - Result Display: Shows detected data with scan engine information
Performance #
- Frame Rate: ~8 FPS processing rate (120ms throttle)
- Memory: Efficient YUV420 to NV21 conversion
- Battery: Minimal drain through frame throttling
- Isolate Processing: Image enhancement runs on separate thread
API Reference #
QrScannerHybrid #
Main widget that provides QR scanning functionality.
Constructor Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
onDetected |
OnQrCodeDetected? |
null |
Callback when QR code is detected. Receives (String data, String engine) |
onClose |
VoidCallback? |
null |
Callback when scanner is closed |
config |
ScannerConfig |
ScannerConfig() |
UI configuration options |
autoClose |
bool |
false |
Automatically close scanner after detection |
OnQrCodeDetected Callback
typedef OnQrCodeDetected = void Function(String data, String engine);
data: The scanned QR code contentengine: The scanning engine that detected it ("ML Kit Live"or"ZXing Enhanced")
ScannerConfig #
UI configuration class for customizing the scanner appearance.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
borderColor |
Color |
Colors.green |
Color of the scan area border |
borderWidth |
double |
3.0 |
Width of the scan area border |
borderRadius |
double |
16.0 |
Border radius of the scan area |
scanAreaSize |
double |
0.7 |
Size of scan area as fraction of screen width (0.0-1.0) |
overlayColor |
Color |
Colors.black54 |
Background overlay color |
showStatusText |
bool |
true |
Show scanning status text |
title |
String? |
null |
AppBar title (defaults to "QR Scanner") |
showAppBar |
bool |
true |
Show the AppBar |
appBarColor |
Color? |
null |
AppBar background color (defaults to black) |
showTorchToggle |
bool |
true |
Show torch/flashlight toggle button |
Example Configuration
const ScannerConfig(
title: 'My Custom Scanner',
borderColor: Colors.purple,
borderWidth: 4,
borderRadius: 20,
scanAreaSize: 0.65,
appBarColor: Colors.purple,
overlayColor: Colors.black45,
showStatusText: true,
showTorchToggle: true,
)
Return Value #
When the scanner is closed or auto-closed, it returns:
Map<String, String> {
'data': 'scanned_qr_code_content',
'engine': 'ML Kit Live' // or 'ZXing Enhanced'
}
Access via Navigator.pop() result:
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => QrScannerHybrid()),
);
if (result != null && result is Map<String, String>) {
String data = result['data']!;
String engine = result['engine']!;
}
Troubleshooting #
Camera Permission Denied #
Ensure you've added platform-specific permissions (see Platform Setup).
ML Kit Not Working on Android #
Verify minSdkVersion is 21 or higher in android/app/build.gradle.
Black Screen on iOS #
Check that NSCameraUsageDescription is added to Info.plist.
QR Code Not Detected #
- Ensure adequate lighting or use the built-in torch
- Hold device steady and keep QR code within the green frame
- Try different distances from the QR code
- The scanner will automatically try enhanced mode after a few seconds
Examples #
Check the example directory for a complete working application.
Roadmap #
- ✅ Customizable callbacks for detection events
- ✅ Configurable scan area and overlay
- ✅ Custom UI theming options
- ❌ Support for multiple barcode formats (beyond QR codes)
- ❌ Batch scanning mode
- ❌ Gallery image scanning
- ❌ Scan history management
- ❌ QR code generation
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Credits #
This package uses:
- google_mlkit_barcode_scanning for ML Kit integration
- flutter_zxing for ZXing scanning
- camera for camera control
- image for image processing
Support #
For issues and feature requests, please visit the issue tracker.

