scan_snap
A simple, customizable, and high-performance QR and barcode scanner widget for Flutter. Easily decode codes from the live camera stream or from image files.
π This package is a maintained and improved fork of the popular
scan
plugin by chavesgu.
β¨ Features
- Embedded Widget: Embed a live scanner directly into your widget tree with the
ScanView
widget. - Customizable: Easily adjust the scan area size and the animated scan line color.
- File Scanning: Decode a QR/barcode from an image file path using
Scan.parse()
. - Full Camera Control: Pause, resume, and toggle the camera's torch using a
ScanController
. - Native Performance: Utilizes CameraX on Android and AVFoundation on iOS for optimal performance.
- π Huawei HMS Support: Optional integration with Huawei Scan Kit for devices without Google Play Services.
π Getting Started
1. Add Dependency
Add the package to your pubspec.yaml
dependencies:
dependencies:
scan_snap: ^0.0.1 # Replace with the latest version
Then, import the package in your Dart code:
import 'package:scan_snap/scan.dart';
2. Platform Setup
You need to add permissions to access the camera and photo library.
ο£Ώ iOS
Add the following keys to your ios/Runner/Info.plist
file:
<key>NSCameraUsageDescription</key>
<string>This app requires camera access to scan QR codes.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app requires photo library access to scan QR codes from images.</string>
<!-- Required for Flutter Platform Views -->
<key>io.flutter.embedded_views_preview</key>
<true/>
Also, ensure your minSdkVersion
in android/app/build.gradle
is set to at least 23.
// in android/app/build.gradle
android {
defaultConfig {
...
minSdkVersion 21
...
}
}
π Huawei Mobile Services (HMS) Support
This plugin includes optional support for Huawei Mobile Services (HMS), allowing the scanner to work on Huawei devices without Google Play Services (like devices with HarmonyOS).
When to Enable HMS
Enable HMS support if:
- Your app will be distributed on Huawei AppGallery
- You want to support Huawei devices without Google Play Services
- You're targeting markets where Huawei devices are popular
Setup HMS (Optional)
Step 1: Create a Huawei Developer Account
- Go to AppGallery Connect
- Create an account and set up a new project
- Add your app to the project with your package name
Step 2: Download Configuration File
- In AppGallery Connect, go to Project Settings β General Information
- Download the
agconnect-services.json
file - Place it in your
android/app/
directory
your_app/
βββ android/
βββ app/
βββ build.gradle.kts
βββ agconnect-services.json β Place here
Step 3: Configure Gradle Files
android/settings.gradle.kts:
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven { url = uri("https://developer.huawei.com/repo/") } // Add this
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.huawei.agconnect") {
useModule("com.huawei.agconnect:agcp:${requested.version}")
}
}
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
repositories {
google()
mavenCentral()
maven { url = uri("https://developer.huawei.com/repo/") } // Add this
}
}
android/build.gradle.kts:
buildscript {
repositories {
google()
mavenCentral()
maven { url = uri("https://developer.huawei.com/repo/") } // Add this
}
dependencies {
classpath("com.android.tools.build:gradle:8.9.1")
classpath("com.huawei.agconnect:agcp:1.9.1.301") // Add this
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url = uri("https://developer.huawei.com/repo/") } // Add this
}
}
android/app/build.gradle.kts:
plugins {
id("com.android.application")
id("kotlin-android")
id("com.huawei.agconnect") // Add this
id("dev.flutter.flutter-gradle-plugin")
}
android {
// ... your existing configuration
defaultConfig {
applicationId = "com.your.package" // Must match agconnect-services.json
// ...
}
}
dependencies {
// Your existing dependencies...
}
Important Notes
- HMS is automatically enabled if
agconnect-services.json
is present in your project - If the file is not found, the plugin will compile without HMS support (using only Google ML Kit/ZXing)
- The
applicationId
in yourbuild.gradle.kts
must match thepackage_name
inagconnect-services.json
π¦ Basic Usage
Live Scanner with ScanView
The best way to use the scanner is within a StatefulWidget
. Here is a complete example of a scanner screen.
import 'package:flutter/material.dart';
import 'package:scan_snap/scan.dart';
class ScanScreen extends StatefulWidget {
const ScanScreen({super.key});
@override
State<ScanScreen> createState() => _ScanScreenState();
}
class _ScanScreenState extends State<ScanScreen> {
final ScanController _controller = ScanController();
void _onCapture(String data) {
// When a QR is captured, stop the scanner and return to the previous screen
// with the captured data.
print('Captured data: $data');
if (mounted) {
Navigator.of(context).pop(data);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Scan Code')),
body: ScanView(
controller: _controller,
scanAreaScale: 0.7, // Scan area is 70% of the view size
scanLineColor: Colors.tealAccent,
onCapture: _onCapture,
),
);
}
}
Controlling the Camera
You can control the camera via the ScanController
passed to the ScanView
.
// Pause image analysis (the preview stream continues)
controller.pause();
// Resume image analysis
controller.resume();
// Toggle the flashlight on or off
controller.toggleTorchMode();
// Safely shut down and release the camera (used when leaving the screen)
await controller.shutdown();
Scanning from an Image File
Use the static Scan.parse()
method to decode a QR/barcode from a saved image on the device. This is ideal for use with plugins like image_picker
.
import 'package:image_picker/image_picker.dart';
import 'package:scan_snap/scan.dart';
// ...
// Example of how to pick an image from the gallery and scan it
Future<void> scanFromGallery() async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
final String? result = await Scan.parse(image.path);
if (result != null) {
print('Result from image: $result');
}
}
}
π Proguard Rules (Android)
If you use Proguard/R8 to shrink and obfuscate your release app, add the following rules to your android/app/proguard-rules.pro
file to prevent breaking ZXing and CameraX functionality.
# Rules for ZXing (the decoding library)
-keep class com.google.zxing.** { *; }
# Rules for CameraX (usually not needed but recommended for safety)
-keep public class androidx.camera.core.** {
public *;
}
-keep class * implements androidx.camera.core.ImageAnalysis$Analyzer {
*;
}
# Rules for Huawei HMS (if using HMS support)
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
-dontwarn com.huawei.**
π Acknowledgements
This plugin is based on the work of the original scan
plugin created by chavesgu.