multi_qr_tracker 0.5.0
multi_qr_tracker: ^0.5.0 copied to clipboard
A Flutter package for detecting and tracking multiple QR codes simultaneously on Android and iOS with adaptive UI overlays. Native CameraX and AVFoundation implementation.
multi_qr_tracker #
A powerful Flutter package for detecting and tracking multiple QR codes simultaneously with adaptive UI overlays.
๐ฏ Why This Package? #
This package was created to provide reliable multi-QR code detection with native implementations using CameraX (Android) and AVFoundation (iOS).
Current Status:
- โ Android platform support
- โ iOS platform support
- โ Portrait orientation
- ๐ง Landscape orientation coming in future updates
โจ Features #
- ๐ Multi-QR Code Detection: Detect and track multiple QR codes simultaneously in real-time
- ๐ Dynamic Borders: Borders automatically adjust size as you move closer or further from QR codes
- ๐ Rotated Border Rendering: Borders rotate to match QR code orientation at any angle
- ๐จ Smart Border Coloring: Fixed color or auto-mode (same QR value = same color)
- ๐ฏ Adaptive Scan Buttons: Full buttons with icon and text for large QR codes, icon-only for small ones
- ๐ฆ Smart Torch Control: Three modes - off, auto (turns on in dark), or manual button control
- โฑ๏ธ Automatic Scanning: Configurable auto-scan after delay (default 2 seconds, can disable)
- ๐ฎ Camera Lifecycle Control: Optional controller for start/stop and battery optimization
- ๐ฏ Optional Scan Frame: Show corner indicators to guide users where to position QR codes
- ๐จ Fully Customizable: Colors, border width, padding, corner radius, scan frame style, and more
- ๐ High Performance: Smooth real-time tracking with CameraX and ML Kit Barcode Scanning
- ๐ Zero Setup Required: Automatic permission handling - no AndroidManifest.xml configuration needed
- ๐ค Native Implementation: CameraX (Android) and AVFoundation (iOS) for optimal performance
- ๐ฑ Current Support: Android (API 21+) and iOS (13.0+) in portrait orientation
- ๐ฎ Coming Soon: Landscape orientation
๐ฑ Screenshots #
|
With borderColor All borders use specified color |
Without borderColor Auto colors (same QR = same color) |
๐ Getting Started #
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
multi_qr_tracker: ^0.5.0
Then run:
flutter pub get
Platform Setup #
Android
No manual setup required! The package automatically:
- โ Declares camera permissions in the manifest (merged automatically)
- โ Requests runtime camera permissions when needed
- โ Handles permission results
Just ensure your minimum SDK version is 21 or higher in android/app/build.gradle:
minSdkVersion 21
iOS
Add the NSCameraUsageDescription key to your ios/Runner/Info.plist file. This explains why your app needs camera access:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>
๐ก Usage #
Basic Example #
import 'package:flutter/material.dart';
import 'package:multi_qr_tracker/multi_qr_tracker.dart';
class QRScannerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('QR Scanner')),
body: MultiQrTrackerView(
onQrCodeScanned: (String value) {
print('Scanned: $value');
// Handle scanned QR code
},
// Auto-scan enabled by default after 2 seconds
),
);
}
}
Border Color Modes #
// Fixed color - all borders use specified color
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
borderColor: Colors.green, // All borders green
)
// Auto color mode - same QR value gets same color
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
// borderColor: null (default), generates unique colors
)
Camera Control with Controller #
class _ScannerScreenState extends State<ScannerScreen> {
final _controller = MultiQrTrackerController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _navigateToDetails() {
// Stop camera when navigating away (saves battery)
_controller.stop();
Navigator.push(context, /* ... */);
}
void _onReturn() {
// Resume camera when returning
_controller.start();
}
@override
Widget build(BuildContext context) {
return MultiQrTrackerView(
controller: _controller,
onQrCodeScanned: (value) => print(value),
);
}
}
Benefits of using a controller:
- ๐ Battery Saving: Stop camera when not visible (tabs, modals, navigation)
- โก Performance: Pause processing when scanner is in background
- ๐ฎ Control: Programmatic start/stop and torch control
- ๐ฆ Torch Toggle:
controller.toggleTorch()orcontroller.setTorch(enabled: true)
Automatic Scanning #
// Default: auto-scan after 2 seconds (enabled by default)
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
)
// Custom delay: auto-scan after 5 seconds
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
autoScanConfig: AutoScanConfig(scanDelay: Duration(seconds: 5)),
)
// Manual only: disable auto-scan (requires button press)
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
autoScanConfig: AutoScanConfig(enabled: false),
)
Torch (Flashlight) Control #
// Manual control - shows a torch button
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
torchMode: TorchMode.manual,
)
// Auto mode - turns on in low light
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
torchMode: TorchMode.auto,
)
// Always off (default)
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
torchMode: TorchMode.off,
)
// Custom position (topLeft, topRight, bottomLeft, bottomRight)
MultiQrTrackerView(
onQrCodeScanned: (value) => print(value),
torchMode: TorchMode.manual,
torchButtonPosition: TorchButtonPosition.topRight,
)
Advanced Example #
MultiQrTrackerView(
onQrCodeScanned: (String value) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Scanned: $value')),
);
},
// Torch control: off, auto, or manual
torchMode: TorchMode.manual,
torchButtonPosition: TorchButtonPosition.bottomRight,
// Customize QR code borders
borderColor: Colors.blue,
borderWidth: 4.0,
borderPadding: 12.0,
cornerRadius: 20.0,
// Customize scan buttons
scanButtonColor: Colors.green,
iconColor: Colors.white,
// Optional scan frame with corner indicators
showScanFrame: true,
scanFrameColor: Colors.white,
scanFrameSize: 250.0,
scanFrameCornerLength: 40.0,
scanFrameCornerWidth: 4.0,
// Error handling
onCameraError: (String error) {
print('Camera error: $error');
},
onPermissionDenied: () {
print('Camera permission denied');
},
)
๐จ Customization #
| Parameter | Type | Default | Description |
|---|---|---|---|
onQrCodeScanned |
Function(String) |
required | Callback when QR code is scanned |
controller |
MultiQrTrackerController? |
null |
Optional controller for programmatic camera control |
autoScanConfig |
AutoScanConfig |
enabled: true, delay: 2s |
Auto-scan configuration: enabled flag and delay duration |
torchMode |
TorchMode |
TorchMode.off |
Torch control: off, auto, or manual |
torchButtonPosition |
TorchButtonPosition |
bottomRight |
Torch button position: topLeft, topRight, bottomLeft, bottomRight |
borderColor |
Color? |
null |
Border color: specific color or null for auto-mode |
borderWidth |
double |
3.0 |
Width of border lines |
borderPadding |
double |
8.0 |
Extra padding around QR codes |
cornerRadius |
double |
12.0 |
Border corner radius |
scanButtonColor |
Color |
Colors.blue |
Scan button background color |
iconColor |
Color |
Colors.white |
Scan button icon color |
torchButtonBackgroundColor |
Color |
Colors.black54 |
Torch button background color (manual mode) |
torchButtonIconColor |
Color |
Colors.white |
Torch button icon color (manual mode) |
showScanFrame |
bool |
false |
Show scan frame with corner indicators |
scanFrameColor |
Color |
Colors.white |
Color of scan frame corners |
scanFrameSize |
double |
250.0 |
Size of scan frame (width and height) |
scanFrameCornerLength |
double |
40.0 |
Length of corner lines |
scanFrameCornerWidth |
double |
4.0 |
Thickness of corner lines |
onCameraError |
Function(String)? |
null |
Camera error callback |
onPermissionDenied |
VoidCallback? |
null |
Permission denied callback |
๐ How It Works #
- Automatic Permission Handling: Requests camera permission at runtime when first initialized (both platforms)
- Native Camera: Uses CameraX (Android) and AVFoundation (iOS) for camera preview and capture
- Detection: ML Kit Barcode Scanning (Android) and AVCaptureMetadataOutput (iOS) detect QR codes in real-time
- Auto-Scan Timer: Automatically triggers scanning after configured delay (default 2 seconds)
- Coordinate Mapping: Transforms camera coordinates to screen coordinates with BoxFit.cover
- Border Rendering: Draws dynamic borders using corner points to match QR code rotation
- Adaptive UI: Automatically switches between full button and icon-only based on QR code size
- Scan Frame: Optional corner indicators to guide user positioning
๐ง API Reference #
MultiQrTrackerView #
The main widget for QR code detection.
MultiQrTrackerView({
Key? key,
required Function(String value) onQrCodeScanned,
Color? borderColor,
double borderWidth = 3.0,
double borderPadding = 8.0,
double cornerRadius = 12.0,
Color scanButtonColor = Colors.blue,
Color iconColor = Colors.white,
bool showScanFrame = false,
Color scanFrameColor = Colors.white,
double scanFrameSize = 250.0,
double scanFrameCornerLength = 40.0,
double scanFrameCornerWidth = 4.0,
Function(String error)? onCameraError,
VoidCallback? onPermissionDenied,
})
QrCodeInfo #
Model class containing QR code information:
class QrCodeInfo {
final String value;
final Rect boundingBox;
final List<Offset> corners;
Offset get center;
double get width;
double get height;
bool get isLargeEnoughForFullButton;
}
๐ Example App #
Check out the example directory for a complete demo app showing:
- Multiple QR code detection
- Real-time orientation switching
- Dynamic color customization
- Scan history tracking
- Error handling
Run the example:
cd example
flutter run
๐งช Testing #
The package includes comprehensive tests with >90% coverage:
flutter test --coverage
๐ค Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
๐ License #
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Support #
If you find this package helpful, please:
- โญ Star the repository
- ๐ Report bugs and request features via GitHub Issues
- ๐ฐ Sponsor the project
๐จโ๐ป Author #
Dhia Bechattaoui
- GitHub: @Dhia-Bechattaoui
- Sponsor: github.com/sponsors/Dhia-Bechattaoui
๐ Acknowledgments #
- Built with CameraX for native Android camera integration
- Built with AVFoundation for native iOS camera integration
- Uses ML Kit Barcode Scanning for Android QR code detection
- Uses AVCaptureMetadataOutput for iOS QR code detection
- Inspired by the need for reliable multi-QR code scanning in Flutter apps
๐ Changelog #
See CHANGELOG.md for a list of changes.
๐ฎ Roadmap #
- โ iOS platform support
- โฌ Landscape orientation support
- โฌ Auto-rotate support
- โฌ Barcode format detection (EAN, Code128, etc.)
- โ Flashlight control (off, auto, manual modes)
- โฌ Zoom controls
- โฌ Image picker scanning
- โฌ Custom overlay widgets
Made with โค๏ธ by Dhia Bechattaoui