ultra_qr_scanner 3.0.2 copy "ultra_qr_scanner: ^3.0.2" to clipboard
ultra_qr_scanner: ^3.0.2 copied to clipboard

Ultra-fast, low-latency QR code & Barcode scanner plugin for Flutter with native performance optimization.

Ultra QR Scanner ๐Ÿ“ฑโšก #

pub package GitHub Platform

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:

dependencies:
  ultra_qr_scanner: ^3.0.2
flutter pub get

๐Ÿƒโ€โ™‚๏ธ Quick Start #

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());
}
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) #

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) #

// 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 #

Scanning Modes #

The widget supports two main scanning modes:

๐Ÿค– Auto-Start Mode (Instant Scanning)

Perfect for quick scanning scenarios where you want immediate results:

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:

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:

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 #

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)

// Perfect for: Payment apps, quick actions, URL scanning
UltraQrScannerWidget(
  onCodeDetected:(code , type) => processPayment(code),
  autoStart: true,
  showStartStopButton: false,
  autoStop: true,
)

๐Ÿ“ท Traditional Scanner (User Control)

// Perfect for: Document scanning, batch operations, careful scanning
UltraQrScannerWidget(
  onCodeDetected:(code , type) => addToList(code),
  autoStart: false,
  showStartStopButton: true,
  autoStop: false, // Continuous scanning
)
// 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 #

// 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;
  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 #

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 #

// โœ… 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,
)
// โœ… 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 #

// โœ… 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 #

[2.1.0] - Latest #

  • ๐Ÿค– Auto-start scanning mode - Begin scanning immediately when widget appears
  • ๐Ÿ‘† 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 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 #

๐Ÿ“ž Support #


Made with โค๏ธ for the Flutter community
If this package helped you, please consider giving it a โญ on GitHub and a ๐Ÿ‘ on pub.dev
6
likes
150
points
619
downloads

Publisher

unverified uploader

Weekly Downloads

Ultra-fast, low-latency QR code & Barcode scanner plugin for Flutter with native performance optimization.

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on ultra_qr_scanner

Packages that implement ultra_qr_scanner