Skip to main content

zp_qr_scanner 1.3.0 copy "zp_qr_scanner: ^1.3.0" to clipboard
zp_qr_scanner: ^1.3.0 copied to clipboard

A high-performance Flutter QR scanner plugin powered by native camera textures on iOS (AVFoundation) and Android (CameraX + ML Kit).

zp_qr_scanner #

pub package License: MIT

A high-performance Flutter QR scanner plugin powered by native camera textures on iOS (AVFoundation) and Android (CameraX + bundled ML Kit), streamed into Flutter via TextureRegistry.

✨ Features #

  • 📱 iOS & Android: AVFoundation on iOS, CameraX + bundled ML Kit on Android (no Google Play Services required).
  • ⚡ High Performance: Native camera texture streaming directly into Flutter via Texture(textureId: ...), avoiding expensive platform view and image conversion overhead.
  • 🎯 Smooth Real-time Tracking: Automatically detects and tracks QR corners with smooth bounding box and scanning animations. The preview freezes on the exact frame the QR was detected in, so the corners always line up.
  • 🔦 Torch & Focus Controls: Built-in support for toggling flashlight and manual tap-to-focus.
  • 🔍 Zoom: Pinch-to-zoom in QrScannerView, or set a zoom level such as 1.0, 2.0, 3.0 from code.
  • 📳 Haptic Feedback: Built-in haptic feedback on successful scans.
  • 📱 Low Memory & Battery Efficient: Clean lifecycle management with automatic resume and pause.

🚀 Getting Started #

1. Add dependency #

Add zp_qr_scanner to your pubspec.yaml:

dependencies:
  zp_qr_scanner: ^1.3.0

Or install it via CLI:

flutter pub add zp_qr_scanner

2. Platform Setup #

iOS Setup

Add the camera permission description to your ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>We need access to your camera to scan QR codes and barcodes.</string>

Note: Requires iOS 15.5 or higher.

Android Setup

No extra setup is needed: the plugin declares the CAMERA permission and requests it at runtime when start() is called.

  • minSdkVersion 21 or higher.
  • Your activity must be a FlutterActivity or FlutterFragmentActivity (the default for Flutter apps).
  • The QR model is bundled (ML Kit), so scanning works without Google Play Services; it adds roughly 2–3 MB per ABI to the APK.

App size impact #

Measured with ./.build/analyze-size.sh (Flutter 3.29.0, release build, empty app vs. app using QrScannerView):

Platform Added size
Android arm64-v8a ~3.9 MB
Android armeabi-v7a ~3.6 MB
iOS arm64 ~0.2 MB

On Android most of it is the bundled ML Kit barcode model; iOS uses the system AVFoundation framework.


📖 Usage #

Basic Scanner View #

Use QrScannerView to display a full-featured scanner screen:

import 'package:flutter/material.dart';
import 'package:zp_qr_scanner/zp_qr_scanner.dart';

class ScanPage extends StatelessWidget {
  const ScanPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: QrScannerView(
        onScanned: (String value) async {
          // Handle scan result
          await showDialog(
            context: context,
            builder: (ctx) => AlertDialog(
              title: const Text('Scanned Result'),
              content: Text(value),
              actions: [
                TextButton(
                  onPressed: () => Navigator.of(ctx).pop(),
                  child: const Text('OK'),
                ),
              ],
            ),
          );
          // Once the Future finishes, scanner resumes automatically!
        },
      ),
    );
  }
}

Scan frame position

The idle scan frame is centered by default. Use scanBoxAlignment to move it and scanBoxOffset to fine-tune it in logical pixels:

QrScannerView(
  onScanned: _handleScanned,
  scanBoxAlignment: const Alignment(0, -0.3), // a bit above center
  scanBoxOffset: const Offset(0, 16),         // then 16px down
)

The whole camera frame is still scanned, so a QR code outside the frame is detected too.

Zoom

Pinch with two fingers to zoom in and out (set enablePinchZoom: false to disable it). To offer fixed zoom levels, call ZpQrScanner.setZoom and listen to ZpQrScanner.zoom:

// e.g. from a "2x" button
await ZpQrScanner.setZoom(2.0);

ValueListenableBuilder<double>(
  valueListenable: ZpQrScanner.zoom,
  builder: (_, zoom, __) => Text('${zoom.toStringAsFixed(1)}x'),
)

1.0 is the main (wide) lens. The level is clamped to ZpQrScanner.minZoom..ZpQrScanner.maxZoom (available after the camera starts): minZoom is below 1.0 on devices with an ultra-wide lens, and maxZoom is capped at 10.0. On Android, and on iOS devices with a single wide lens, the camera may start slightly zoomed in (up to 2.0) to keep small QR codes in focus.

Scan control

Pause QR detection while keeping the camera preview running (e.g. while some other UI covers the camera), and recover a camera that got stuck:

// Pause detection; camera/preview keep running
await ZpQrScanner.stopScan();

// Resume detection
await ZpQrScanner.resumeScan();

ValueListenableBuilder<bool>(
  valueListenable: ZpQrScanner.isScanning,
  builder: (_, isScanning, __) => Text(isScanning ? 'Scanning' : 'Paused'),
)

// Recover a stuck camera: restarts the session only if it isn't
// actually showing a fresh frame anymore.
await ZpQrScanner.restart();
Method What it does
stop() / resume() Full camera lifecycle: stop() releases the camera and texture; resume() only un-freezes the preview after a detected code — unrelated to pausing detection.
stopScan() / resumeScan() Pauses/resumes QR detection only. The camera and preview keep running normally.
restart() Recovery: checks whether the camera is actually showing a fresh frame, and only tears down and restarts the session if it isn't. A no-op (besides returning the current state) if everything is already fine.

QrScannerView already reacts to isScanning and to texture changes from restart(), so these are safe to call even while a QrScannerView is on screen — including from outside the widget that created it.

restart() only recovers a camera that is already running (or was running and got stuck) — it won't turn the camera on by itself. Calling it before start(), or after stop(), throws a PlatformException(code: 'not_started'); calling it twice before the first call finishes may throw PlatformException(code: 'restart_in_progress') on Android. Call start() first if you want to begin a new session.


Low-level API (ZpQrScanner) #

If you want custom UI or manual camera control:

// Start camera session and get texture metadata
final QrTexture texture = await ZpQrScanner.start();
print('Texture ID: ${texture.id}, Size: ${texture.size}');

// Listen to scanned results stream
final subscription = ZpQrScanner.results.listen((QrScanResult result) {
  print('Scanned value: ${result.value}');
  print('Corners: ${result.corners}');
});

// Toggle torch / flashlight
await ZpQrScanner.setTorch(true);

// Focus at a specific point (normalized 0.0 - 1.0)
await ZpQrScanner.focus(const Offset(0.5, 0.5));

// Zoom (clamped to ZpQrScanner.minZoom..ZpQrScanner.maxZoom)
final double applied = await ZpQrScanner.setZoom(2.0);

// Pause and resume
await ZpQrScanner.stop();
await ZpQrScanner.resume();

// Pause/resume detection only (camera keeps running), and recover a stuck camera
await ZpQrScanner.stopScan();
await ZpQrScanner.resumeScan();
await ZpQrScanner.restart();

🛠️ Example #

Check out the complete sample project in the example/ directory.


📄 License #

This project is licensed under the MIT License - see the LICENSE file for details.

1
likes
150
points
571
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A high-performance Flutter QR scanner plugin powered by native camera textures on iOS (AVFoundation) and Android (CameraX + ML Kit).

Repository (GitHub)
View/report issues

Topics

#qr-code #barcode #scanner #camera

License

MIT (license)

Dependencies

flutter

More

Packages that depend on zp_qr_scanner

Packages that implement zp_qr_scanner