Flutter ZXing is a plugin for scanning and generating barcodes using the ZXing barcode scanning library. The plugin is implemented using the Dart FFI (Foreign Function Interface) and the zxing-cpp library and allows you to integrate barcode scanning and generation functionalities into your Flutter apps.
In this tutorial, we’ll walk you through the process of setting up a Flutter project and implementing an Android barcode scanner using flutter_zxing.
Prerequisites
Before you begin, ensure you have the following tools and components installed:
- Android Studio or Visual Studio Code: You need an Integrated Development Environment (IDE) to write and run your Flutter code. Android Studio is recommended for its support for Android development.
- Android device or emulator: You will need a physical Android device or an Android emulator set up in your IDE to test your application.
Setting up the Flutter environment
To start, you have to install the Flutter SDK:
- Visit the Flutter installation guide.
- Select your operating system from the available options.
- Choose Android as your development platform.
- Follow the instructions under Download and Install to download and unzip the Flutter SDK. When unzipping the file, pay attention to any path restrictions mentioned in the guide.
- If you’re a Windows user, after unzipping the SDK, make sure to update your Windows Path Variable as detailed in the guide.
Next, you’ll need to set up your Android development environment:
- Visit the Flutter guide for Android setup.
- Follow the instructions specific to your situation—whether you’re a new or existing Android Studio user. Choose the guide that best suits you.
- Agree to the Flutter Android licenses by following the license agreement instructions.
- Finally, verify your development setup to ensure everything is configured correctly.
Creating the app
The following steps cover all the steps to create the Flutter barcode scanner app.
Step 1: Create the project
Before diving into the barcode scanner functionality, let’s start by setting up a basic Flutter project. This will lay the groundwork for all the features we’ll add later on. Follow these steps to get your project up and running:
- Open your terminal and access the directory where you want to create the app.
- Create a new Flutter project by running the following command:
flutter create barcode_scanner
cd barcode_scanner
flutter run
Step 2: Install the Flutter ZXing plugin
With your basic Flutter app up and running, it’s time to start building the barcode scanner functionality. To do this, you’ll use the Flutter ZXing plugin. Follow these steps to install the plugin and configure your app:
- Open your project in Android Studio. Once it is open, switch to the Project Files view to locate the necessary folders and files easily.
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
flutter_zxing: ^1.7.0
flutter pub get
Step 3: Configure the app
Now that the basics are set up, it’s time to configure the app as a barcode scanner. Start by opening the main.dart file in the lib folder. Delete the default Flutter code to begin building your barcode scanner app from scratch.
3.1: Import the packages and create the main function
The first step in configuring your app is to import the required packages and set up the main()
function:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_zxing/flutter_zxing.dart';
void main() {
runApp(const MyApp());
}
3.2: Create the MyApp class
Next, you’ll create the MyApp
class, which is a stateless widget that serves as the root of your application. This class returns a MaterialApp
widget, providing the basic structure and theme for your app.
MaterialApp
: A wrapper that includes apptitle
,debugShowCheckedModeBanner,
andhome
settings.home
: Points to theDemoPage
widget, which will be the main screen of the app.
Below is the code to set up the MyApp
class:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter ZXing Barcode Scanner',
home: DemoPage(),
);
}
}
3.3. Create the DemoPage widget
The DemoPage
widget is the core of the barcode scanner app, handling its main functionality. In Flutter, when a widget needs to manage a mutable state, you use a StatefulWidget
along with its corresponding State
class. In this case, the mutable state is necessary to track the scanned barcode, which determines whether to display the barcode scan result.
The DemoPage
setup consists of:
DemoPage StatefulWidget
: Manages the state of the app’s main screen._DemoPageState
: Contains the logic and functions behind the main screen, including tracking the barcode scan result. Theresult
is stored as a nullableCode
object.
The following table lists the methods within the _DemoPageState
class:
Method | Description | Functionality |
---|---|---|
build(BuildContext) | The primary method for building the widget tree. It checks the platform support and either shows the scanner interface or an unsupported platform message. | The build method is called whenever setState is invoked, triggering a rebuild of the widget tree. It constructs the UI based on the current state. If the platform supports the camera, it displays either the ScanResultWidget (if a valid scan result exists) or the scanner interface (by calling _buildScanner ). If not, it displays the UnsupportedPlatformWidget . ScanResult and UnsupportedPlatform are external widgets which you’ll create in the following tutorial sections. |
_isCameraSupported() | Helper method to check if the current platform supports the camera. | Returns a boolean value indicating whether the current platform supports camera functionality. It specifically checks for iOS and Android platforms, which are supported by the flutter_zxing library. |
_buildScanner() | Helper method that returns the ReaderWidget , which is used to scan barcodes. | Constructs the scanner interface using the ReaderWidget . It configures the scanner with parameters such as resolution, lens direction, and scan format. It also provides callback methods (onScan , onScanFailure , onControllerCreated ) to handle scan results and errors. The ReaderWidget is provided by the flutter_zxing library. For a list of all configurations available, access the GitHub repository. |
_onControllerCreated(_, Exception? error) | Callback method triggered when the scanner controller is created. Handles any errors that occur during the controller’s creation. | Called when the ReaderWidget ‘s controller is created. If an error occurs during creation, such as permission issues, it calls _showMessage to display an error message to the user. |
_onScanSuccess(Code? code) | Callback method that is called when a barcode is successfully scanned. It updates the result state and triggers a UI rebuild. | Triggered when a barcode is successfully scanned. It updates the result variable with the scanned code data and calls setState to rebuild the widget tree. The UI is then updated to display the scan result using ScanResultWidget . |
_onScanFailure(Code? code) | Callback method that handles scan failures. It updates the result state and displays an error message if available. | Triggered when a scan attempt fails. It updates the result variable with the failed code data and calls setState to rebuild the widget tree. If the failed code contains an error message, it is displayed to the user via _showMessage . |
_showMessage(BuildContext, String message) | Helper method that displays a SnackBar with a provided message. | Displays a message to the user related to errors or important information. It first hides any currently visible SnackBar and then shows a new SnackBar with the specified message. This ensures that the user is notified of any issues or updates during scanning. |
The following code block presents the code for DemoPage
and _DemoPageState
:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter ZXing Barcode Scanner',
debugShowCheckedModeBanner: false,
home: DemoPage(),
);
}
}
class DemoPage extends StatefulWidget {
const DemoPage({super.key});
@override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
Code? result;
@override
Widget build(BuildContext context) {
if (kIsWeb || !_isCameraSupported()) {
return const UnsupportedPlatformWidget();
}
return Scaffold(
appBar: AppBar(title: const Text('Scan Code')),
body: result != null && result?.isValid == true
? ScanResultWidget(
result: result,
onScanAgain: () => setState(() => result = null),
)
: _buildScanner(),
);
}
bool _isCameraSupported() {
return defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.android;
}
Widget _buildScanner() {
return ReaderWidget(
onScan: _onScanSuccess,
onScanFailure: _onScanFailure,
onControllerCreated: _onControllerCreated,
resolution: ResolutionPreset.high,
lensDirection: CameraLensDirection.back,
codeFormat: Format.*any*,
showGallery: false,
cropPercent: 0.7,
toggleCameraIcon: const Icon(Icons.*switch\_camera*),
actionButtonsBackgroundBorderRadius: BorderRadius.circular(10),
);
}
void _onControllerCreated(_, Exception? error) {
if (error != null) {
_showMessage(context, 'Error: $error');
}
}
void _onScanSuccess(Code? code) {
setState(() {
result = code;
});
}
void _onScanFailure(Code? code) {
setState(() {
result = code;
});
if (code?.error?.isNotEmpty == true) {
_showMessage(context, 'Error: ${code?.error}');
}
}
void _showMessage(BuildContext context, String message) {
ScaffoldMessenger.*of*(context).hideCurrentSnackBar();
ScaffoldMessenger.*of*(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
}
For this tutorial, the following configurations are used to define the ReaderWidget
behavior:
Configuration | Description |
---|---|
resolution: ResolutionPreset.high | Sets the camera resolution to high. |
lensDirection: CameraLensDirection.back | Configures the camera to use the back camera. |
codeFormat: Format.any | Allows the scanner to detect any barcode format. |
showGallery: false | Disables the option to select images from the gallery for scanning. It only allows scanning barcodes directly using the camera. |
cropPercent: 0.7 | Defines the percentage of the camera preview used for scanning. Increasing this value will increase the app screen area used to identify barcodes. |
toggleCameraIcon: const Icon(Icons.switch_camera) | Sets the icon used for toggling between front and back cameras |
actionButtonsBackgroundBorderRadius: BorderRadius.circular(10) | Applies a border radius of 10 pixels to the background of action buttons |
Access the GitHub repository for a list of all available ReaderWidget
configurations.
3.4 Create the ScanResult widget
The _DemoPageState
build
method relies on the ScanResultWidget
to display the scan result in the app. This widget also includes a Scan Again button to allow users to restart the scanning process.
To create the ScanResultWidget
, start by creating a new folder named widget inside the lib directory. Inside this folder, add a new file named scan_result_widget.dart. This file will define how the scan result is presented to users. It’s important to note that since the ScanResultWidget
is stateless, it doesn’t manage any internal state. Everything it displays is passed in through its properties.
After creating the file, define the ScanResultWidget
class:
class ScanResultWidget extends StatelessWidget {
const ScanResultWidget({
super.key,
this.result,
this.onScanAgain,
});
final Code? result;
final Function()? onScanAgain;
}
In the above code, the result
is a final
property of type Code?
holding the scan result, and onScanAgain
is a final
property of type Function()?
, which is a callback function triggered when the user presses the Scan Again button.
Next, add the components that will make up the UI. Below is the complete code for the ScanResultWidget
, including its basic UI configuration:
import 'package:flutter/material.dart';
import 'package:flutter_zxing/flutter_zxing.dart';
class ScanResultWidget extends StatelessWidget {
const ScanResultWidget({
super.key,
this.result,
this.onScanAgain,
});
final Code? result;
final Function()? onScanAgain;
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
result?.format?.name ?? '',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 20),
Text(
result?.text ?? '',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 20),
Text(
'Inverted: ${result?.isInverted} Mirrored: ${result?.isMirrored}',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: onScanAgain,
child: const Text('Scan Again'),
),
],
),
),
);
}
}
There are two main elements in the above code:
Text
: Display the barcode format, the scanned text, and additional information.ElevatedButton
: This button allows users to scan again by triggering theonScanAgain
callback.
3.5 Create the Unsupported Platform widget
The _DemoPageState
build
method uses the UnsupportedPlatformWidget
to inform the user if the current device and platform do not support camera usage. To create the UnsupportedPlatformWidget
, create a new file named unsupported_platform_widget.dart.dart inside the widgets folder.
Here’s what your lib folder structure will look like after adding the file:
/lib
|--- main.dart
|--- /widgets
|------ scan\_result\_widget.dart
|------ unsupported\_platform\_widget.dat
To build the UnsupportedPlatformWidget
, use the following code. This widget will display a message to users indicating that their platform isn’t supported, with the message centered on the screen and styled according to the app’s theme.
import 'package:flutter/material.dart';
class UnsupportedPlatformWidget extends StatelessWidget {
const UnsupportedPlatformWidget({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Text(
'This platform is not supported yet.',
style: Theme.of(context).textTheme.titleLarge,
),
);
}
}
Step 4: Testing the app
With the main.dart
file updated and the scan_result_widget.dart
and unsupported_platform_widget.dart
files created, you’re ready to test your barcode scanner app. Follow these steps to get started:
- Connect your Android device to your computer or configure an emulator.
- Select your device or emulator in Android Studio.
- In the Run/Debug selector, choose the main.dart file.
The GIF below demonstrates how the barcode scanner app works. Since the ReaderWidget
is configured with Format.any
, the app successfully identifies both Code 128 and EAN-13 barcode formats. The scanning area is set to 70% of the screen width, which restricts barcode detection to this area. You can adjust this setting through the ReaderWidget
configurations. In addition, the GIF shows that the app will not provide a result if more than one barcode is within the scanning area. It only identifies a barcode when a single barcode is visible.
If you change Format.any
to Format.code128
, the app will exclusively identify Code 128 barcodes. The following GIF demonstrates this behavior. Notice how the app no longer reads EAN-13 barcodes and is quicker at detecting Code 128 barcodes.
🎉 And that’s it! You’ve successfully added barcode scanning functionalities to your Flutter app.
Disadvantages of using the ZXing barcode scanner library
ZXing provides decent performance for basic barcode scanning tasks but sometimes struggles with more challenging scenarios. Its most notable drawbacks as a barcode scanning solution include:
- Scanning accuracy and speed: ZXing struggles with scanning poorly lit or damaged barcodes. It often exhibits low recognition rates for smaller barcodes and can fail to decode them altogether.
- Compatibility issues: ZXing may not perform reliably across all devices, particularly newer models. This has led to frustration among developers who require consistent performance across different platforms.
- Lack of active development: As an open-source project, ZXing has seen limited updates and maintenance in recent years. This stagnation can lead to unresolved bugs and compatibility issues, making it less reliable for commercial applications.
- Integration complexity: Integrating ZXing into your app can be cumbersome, especially for developers who may not be familiar with its architecture. This can lead to longer development times and increased chances of bugs during implementation.
For companies that heavily rely on barcode scanning in their business processes, we recommend using an enterprise-grade solution instead.
Building a Flutter Barcode Scanner with the Scanbot SDK
We developed the Scanbot Barcode Scanner SDK to help enterprises overcome the hurdles presented by free barcode scanning software. Our goal was to have a developer-friendly solution available for a wide range of platforms that consistently delivers high-quality results – even in challenging circumstances.
With the SDK’s Ready-to-Use UI Components, you can even use an AR overlay to display multiple barcodes’ contents directly in the viewfinder, enhancing the scanning experience.
Setting up a Flutter app to scan 1D or 2D barcodes is straightforward. We’re going to follow these steps:
- Prepare the project.
- Install the SDK.
- Initialize the SDK.
- Implement the scanning modules.
- Start scanning barcodes!
Requirements
To develop Flutter applications for Android and iOS, ensure you have the following:
- Flutter SDK: Download the latest version for your OS.
- Dart SDK: No separate installation needed, since it’s integrated with Flutter.
- The right IDEs for your target platforms:
- Android Studio to develop for Android. It includes the Android SDK and AVD Manager.
- Xcode for iOS development on macOS.
- You can also use Visual Studio Code, which supports Flutter plugins.
⚠️ A note to Windows users: A Mac is necessary to build and test iOS apps. Consider using a remote Mac service or a physical Mac as a build server.
1. Preparing the project
First, create a new directory for your project and navigate into it:
mkdir test-flutter
cd test-flutter
Create a new Flutter project:
flutter create test_barcode_scanner
cd test_barcode_scanner
Since we need access to the device camera to scan barcodes, let’s add the necessary camera permissions for Android and iOS.
Add camera permissions to android/app/src/main/AndroidManifest.xml
:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" />
And in ios/Runner/Info.plist
:
<key>NSCameraUsageDescription</key>
<string>We need camera access to scan barcodes.</string>
2. Installing the SDK
Add the Scanbot Flutter Barcode Scanner package to your pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
barcode_scanner: ^5.1.0
Run the following commnand to install the packages:
flutter pub get
💡 Please refer to our changelog for the latest version of the Barcode Scanner SDK.
Now that the project is set up, we can integrate the barcode scanning functionalities.
3. Initializing the SDK
Initialize the SDK in main.dart
:
import 'package:flutter/material.dart';
import 'package:barcode_scanner/scanbot_barcode_sdk_v2.dart';
const BARCODE_SDK_LICENSE_KEY = "";
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
_initScanbotSdk();
}
Future<void> _initScanbotSdk() async {
var config = ScanbotSdkConfig(
licenseKey: BARCODE_SDK_LICENSE_KEY,
loggingEnabled: true,
);
try {
await ScanbotBarcodeSdk.initScanbotSdk(config);
print('Scanbot SDK initialized successfully');
} catch (e) {
print('Error initializing Scanbot SDK: $e');
}
}
@override
Widget build(BuildContext context) {
...
}
💡 Without a license key, our SDK only runs for 60 seconds per session. This is more than enough for the purposes of our tutorial, but if you like, you can generate a license key using your applicationId.
4. Implementing the scanning modes
The SDK’s RTU UI components make it easy to deploy our Flutter Barcode Scanner package’s different scanning modes in your app. Let’s start with the simplest use case: single-barcode scanning.
Implement the barcode scanning functionality:
void _startBarcodeScanning() async {
try {
// Create the default configuration object.
var configuration = BarcodeScannerConfiguration();
// Initialize the use case for single scanning.
var scanningMode = SingleScanningMode();
// Enable and configure the confirmation sheet.
scanningMode.confirmationSheetEnabled = true;
scanningMode.sheetColor = ScanbotColor("#FFFFFF");
// Hide/unhide the barcode image.
scanningMode.barcodeImageVisible = true;
// Configure the barcode title of the confirmation sheet.
scanningMode.barcodeTitle.visible = true;
scanningMode.barcodeTitle.color = ScanbotColor("#000000");
// Configure the barcode subtitle of the confirmation sheet.
scanningMode.barcodeSubtitle.visible = true;
scanningMode.barcodeSubtitle.color = ScanbotColor("#000000");
// Configure the cancel button of the confirmation sheet.
scanningMode.cancelButton.text = "Close";
scanningMode.cancelButton.foreground.color = ScanbotColor("#C8193C");
scanningMode.cancelButton.background.fillColor = ScanbotColor("#00000000");
// Configure the submit button of the confirmation sheet.
scanningMode.submitButton.text = "Submit";
scanningMode.submitButton.foreground.color = ScanbotColor("#FFFFFF");
scanningMode.submitButton.background.fillColor = ScanbotColor("#C8193C");
// Configure other parameters, pertaining to single-scanning mode as needed.
configuration.useCase = scanningMode;
// Set an array of accepted barcode types.
// configuration.recognizerConfiguration.barcodeFormats = [
// scanbotV2.BarcodeFormat.AZTEC,
// scanbotV2.BarcodeFormat.PDF_417,
// scanbotV2.BarcodeFormat.QR_CODE,
// scanbotV2.BarcodeFormat.MICRO_QR_CODE,
// scanbotV2.BarcodeFormat.MICRO_PDF_417,
// scanbotV2.BarcodeFormat.ROYAL_MAIL,
/// .....
// ];
// Configure other parameters as needed.
var result = await ScanbotBarcodeSdk.startBarcodeScanner(configuration);
if(result.operationResult == OperationResult.SUCCESS)
{
// TODO: present barcode result as needed
print(result.value?.items.first.type?.name);
}
} catch (e) {
print('Error: $e');
}
}
Now let’s go to the build
method and add the button on the start screen so it calls our _startBarcodeScanning
method when clicked:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Barcode Scanner'),
),
body: Center(
child: ElevatedButton(
onPressed: _startBarcodeScanning,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start single-barcode scanning"),
),
),
);
}
If you like, you can build and run the app to see if everything is working correctly so far:
flutter run
In the next step, we’re going to insert both the multi-barcode scanning and the AR overlay modules.
Let’s create two more methods, _startBarcodeMultiScanning
and _startAROverlay
:
void _startBarcodeMultiScanning() async {
try {
// Create the default configuration object.
var configuration = BarcodeScannerConfiguration();
// Initialize the use case for multiple scanning.
var scanningMode = MultipleScanningMode();
// Set the counting mode.
scanningMode.mode = MultipleBarcodesScanningMode.COUNTING;
// Set the sheet mode for the barcodes preview.
scanningMode.sheet.mode = SheetMode.COLLAPSED_SHEET;
// Set the height for the collapsed sheet.
scanningMode.sheet.collapsedVisibleHeight = CollapsedVisibleHeight.LARGE;
// Enable manual count change.
scanningMode.sheetContent.manualCountChangeEnabled = true;
// Set the delay before same barcode counting repeat.
scanningMode.countingRepeatDelay = 1000;
// Configure the submit button.
scanningMode.sheetContent.submitButton.text = "Submit";
scanningMode.sheetContent.submitButton.foreground.color =
ScanbotColor("#000000");
// Configure other parameters, pertaining to multiple-scanning mode as needed.
configuration.useCase = scanningMode;
// Set an array of accepted barcode types.
// configuration.recognizerConfiguration.barcodeFormats = [
// BarcodeFormat.AZTEC,
// BarcodeFormat.PDF_417,
// BarcodeFormat.QR_CODE,
// BarcodeFormat.MICRO_QR_CODE,
// BarcodeFormat.MICRO_PDF_417,
// BarcodeFormat.ROYAL_MAIL,
/// .....
// ];
// Configure other parameters as needed.
var result = await ScanbotBarcodeSdk.startBarcodeScanner(configuration);
if(result.operationResult == OperationResult.SUCCESS)
{
// TODO: present barcode result as needed
print(result.value?.items.first.type?.name);
}
} catch (e) {
print('Error: $e');
}
}
void _startAROverlay() async {
try {
// Create the default configuration object.
var configuration = new BarcodeScannerConfiguration();
// Configure the usecase.
var usecase = new MultipleScanningMode();
usecase.mode = MultipleBarcodesScanningMode.UNIQUE;
usecase.sheet.mode = SheetMode.COLLAPSED_SHEET;
usecase.sheet.collapsedVisibleHeight = CollapsedVisibleHeight.SMALL;
// Configure AR Overlay.
usecase.arOverlay.visible = true;
usecase.arOverlay.automaticSelectionEnabled = false;
// Set the configured usecase.
configuration.useCase = usecase;
// Set an array of accepted barcode types.
// configuration.recognizerConfiguration.barcodeFormats = [
// BarcodeFormat.AZTEC,
// BarcodeFormat.PDF_417,
// BarcodeFormat.QR_CODE,
// BarcodeFormat.MICRO_QR_CODE,
// BarcodeFormat.MICRO_PDF_417,
// BarcodeFormat.ROYAL_MAIL,
/// .....
// ];
var result = await ScanbotBarcodeSdk.startBarcodeScanner(configuration);
if (result.operationResult == OperationResult.SUCCESS) {
// TODO: present barcode result as needed
print(result.value?.items.first.type?.name);
}
} catch (e) {
print('Error: $e');
}
}
And let’s not forget to insert the buttons:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Barcode Scanner'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _startBarcodeScanning,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start single-barcode scanning"),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _startBarcodeMultiScanning,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start multi-barcode scanning"),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _startAROverlay,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start the AR overlay"),
),
],
),
),
);
}
Your final main.dart
should look something like this:
import 'package:flutter/material.dart';
import 'package:barcode_scanner/scanbot_barcode_sdk_v2.dart';
const BARCODE_SDK_LICENSE_KEY = "";
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
_initScanbotSdk();
}
Future<void> _initScanbotSdk() async {
var config = ScanbotSdkConfig(
licenseKey: BARCODE_SDK_LICENSE_KEY,
loggingEnabled: true,
);
try {
await ScanbotBarcodeSdk.initScanbotSdk(config);
print('Scanbot SDK initialized successfully');
} catch (e) {
print('Error initializing Scanbot SDK: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Barcode Scanner'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _startBarcodeScanning,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start single-barcode scanning"),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _startBarcodeMultiScanning,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start multi-barcode scanning"),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _startAROverlay,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 40),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text("Start the AR overlay"),
),
],
),
),
);
}
void _startBarcodeScanning() async {
try {
// Create the default configuration object.
var configuration = BarcodeScannerConfiguration();
// Initialize the use case for single scanning.
var scanningMode = SingleScanningMode();
// Enable and configure the confirmation sheet.
scanningMode.confirmationSheetEnabled = true;
scanningMode.sheetColor = ScanbotColor("#FFFFFF");
// Hide/unhide the barcode image.
scanningMode.barcodeImageVisible = true;
// Configure the barcode title of the confirmation sheet.
scanningMode.barcodeTitle.visible = true;
scanningMode.barcodeTitle.color = ScanbotColor("#000000");
// Configure the barcode subtitle of the confirmation sheet.
scanningMode.barcodeSubtitle.visible = true;
scanningMode.barcodeSubtitle.color = ScanbotColor("#000000");
// Configure the cancel button of the confirmation sheet.
scanningMode.cancelButton.text = "Close";
scanningMode.cancelButton.foreground.color = ScanbotColor("#C8193C");
scanningMode.cancelButton.background.fillColor = ScanbotColor("#00000000");
// Configure the submit button of the confirmation sheet.
scanningMode.submitButton.text = "Submit";
scanningMode.submitButton.foreground.color = ScanbotColor("#FFFFFF");
scanningMode.submitButton.background.fillColor = ScanbotColor("#C8193C");
// Configure other parameters, pertaining to single-scanning mode as needed.
configuration.useCase = scanningMode;
// Set an array of accepted barcode types.
// configuration.recognizerConfiguration.barcodeFormats = [
// scanbotV2.BarcodeFormat.AZTEC,
// scanbotV2.BarcodeFormat.PDF_417,
// scanbotV2.BarcodeFormat.QR_CODE,
// scanbotV2.BarcodeFormat.MICRO_QR_CODE,
// scanbotV2.BarcodeFormat.MICRO_PDF_417,
// scanbotV2.BarcodeFormat.ROYAL_MAIL,
/// .....
// ];
// Configure other parameters as needed.
var result = await ScanbotBarcodeSdk.startBarcodeScanner(configuration);
if(result.operationResult == OperationResult.SUCCESS)
{
// TODO: present barcode result as needed
print(result.value?.items.first.type?.name);
}
} catch (e) {
print('Error: $e');
}
}
void _startBarcodeMultiScanning() async {
try {
// Create the default configuration object.
var configuration = BarcodeScannerConfiguration();
// Initialize the use case for multiple scanning.
var scanningMode = MultipleScanningMode();
// Set the counting mode.
scanningMode.mode = MultipleBarcodesScanningMode.COUNTING;
// Set the sheet mode for the barcodes preview.
scanningMode.sheet.mode = SheetMode.COLLAPSED_SHEET;
// Set the height for the collapsed sheet.
scanningMode.sheet.collapsedVisibleHeight = CollapsedVisibleHeight.LARGE;
// Enable manual count change.
scanningMode.sheetContent.manualCountChangeEnabled = true;
// Set the delay before same barcode counting repeat.
scanningMode.countingRepeatDelay = 1000;
// Configure the submit button.
scanningMode.sheetContent.submitButton.text = "Submit";
scanningMode.sheetContent.submitButton.foreground.color =
ScanbotColor("#000000");
// Configure other parameters, pertaining to multiple-scanning mode as needed.
configuration.useCase = scanningMode;
// Set an array of accepted barcode types.
// configuration.recognizerConfiguration.barcodeFormats = [
// BarcodeFormat.AZTEC,
// BarcodeFormat.PDF_417,
// BarcodeFormat.QR_CODE,
// BarcodeFormat.MICRO_QR_CODE,
// BarcodeFormat.MICRO_PDF_417,
// BarcodeFormat.ROYAL_MAIL,
/// .....
// ];
// Configure other parameters as needed.
var result = await ScanbotBarcodeSdk.startBarcodeScanner(configuration);
if(result.operationResult == OperationResult.SUCCESS)
{
// TODO: present barcode result as needed
print(result.value?.items.first.type?.name);
}
} catch (e) {
print('Error: $e');
}
}
void _startAROverlay() async {
try {
// Create the default configuration object.
var configuration = new BarcodeScannerConfiguration();
// Configure the usecase.
var usecase = new MultipleScanningMode();
usecase.mode = MultipleBarcodesScanningMode.UNIQUE;
usecase.sheet.mode = SheetMode.COLLAPSED_SHEET;
usecase.sheet.collapsedVisibleHeight = CollapsedVisibleHeight.SMALL;
// Configure AR Overlay.
usecase.arOverlay.visible = true;
usecase.arOverlay.automaticSelectionEnabled = false;
// Set the configured usecase.
configuration.useCase = usecase;
// Set an array of accepted barcode types.
// configuration.recognizerConfiguration.barcodeFormats = [
// BarcodeFormat.AZTEC,
// BarcodeFormat.PDF_417,
// BarcodeFormat.QR_CODE,
// BarcodeFormat.MICRO_QR_CODE,
// BarcodeFormat.MICRO_PDF_417,
// BarcodeFormat.ROYAL_MAIL,
/// .....
// ];
var result = await ScanbotBarcodeSdk.startBarcodeScanner(configuration);
if (result.operationResult == OperationResult.SUCCESS) {
// TODO: present barcode result as needed
print(result.value?.items.first.type?.name);
}
} catch (e) {
print('Error: $e');
}
}
}
Now let’s build and run the app again so we can try out our new scanning modules.
5. Scanning some barcodes!
Now you can go ahead and scan 1D and 2D barcodes – one after the other, many at the same time, and even with an AR overlay that lets you preview their values!
And if you’re in need of some sample barcodes for testing purposes, we’ve got you covered:
If this tutorial has piqued your interest in integrating barcode scanning functionalities into your Flutter app, make sure to take a look at our SDK’s other neat features in our documentation.
Should you have questions about this tutorial or ran into any issues, we’re happy to help! Just shoot us an email via tutorial-support@scanbot.io.
Happy coding!