DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Developing a Barcode Reader To Make Life Easier
  • How to Create a Live Barcode Scanner Using the Webcam in JavaScript
  • Performance Optimization Techniques in Flutter 3.41 for Mobile App Development
  • Publishing Flutter Packages to JFrog Artifactory

Trending

  • Why Stable RAG Answers Can Still Hide Unstable Evidence
  • Token Attribution Framework for Agentic AI in CI/CD
  • Retesting Best Practices for Agile Teams: A Quick Guide to Bug Fix Verification
  • AI Paradigm Shift: Analytics Without SQL
  1. DZone
  2. Coding
  3. Frameworks
  4. How to Implement Flutter Barcode Scanner From Scratch

How to Implement Flutter Barcode Scanner From Scratch

Since the new Flutter is not compatible with the old one, I refactored the APIs of the Flutter barcode plugin and added a new method to scan by video stream in real-time.

By 
Xiao Ling user avatar
Xiao Ling
·
May. 13, 21 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
9.5K Views

Join the DZone community and get the full member experience.

Join For Free

About two years ago, I wrote an article sharing how to build a Flutter barcode plugin with Dynamsoft Barcode Reader step by step. At that time, Flutter was still under development and only supported Android and iOS. Nowadays, Google has released Flutter 2, which allows developers to build apps for mobile, web, and desktop from a single codebase. If you want to build cross-platform apps, it is worth putting much effort into Flutter from now on. Since the new Flutter is not compatible with the old one, I decide to refactor the APIs of the Flutter barcode plugin and add a new method to support barcode scanning by video stream in real-time.

Flutter Barcode SDK Plugin

In the following paragraphs, I will demonstrate how to develop a Flutter barcode plugin that supports reading barcodes from an image file and image buffer, as well as how to publish the plugin to pub.dev.

Developing Flutter Barcode SDK Plugin With Dynamsoft Barcode Reader

My current plan is to make the plugin work for Android. Therefore, I create the plugin package as follows:

flutter create --org com.dynamsoft --template=plugin --platforms=android -a java flutter_barcode_sdk


To add code for other platforms, such as iOS, to the plugin project, I can run:

flutter create --template=plugin --platforms=ios .


The plugin API is defined in the lib/flutter_barcode_sdk.dart file, which is the bridge between Dart code and platform-specific code. A android/src/main/java/com/dynamsoft/flutter_barcode_sdk/FlutterBarcodeSdkPlugin.java file is generated as the Android entry point.

Dart Code

Let’s get started with lib/flutter_barcode_sdk.dart.

The first step is to define a BarcodeResult class, which contains barcode format, result, and coordinate points, for deserializing JSON data returned from platform-specific code:

Java
 




xxxxxxxxxx
1
40


 
1
class BarcodeResult {
2
  final String format;
3
  final String text;
4
  final int x1;
5
  final int y1;
6
  final int x2;
7
  final int y2;
8
  final int x3;
9
  final int y3;
10
  final int x4;
11
  final int y4;
12

          
13
  BarcodeResult(this.format, this.text, this.x1, this.y1, this.x2, this.y2,
14
      this.x3, this.y3, this.x4, this.y4);
15

          
16
  BarcodeResult.fromJson(Map<dynamic, dynamic> json)
17
      : format = json['format'],
18
        text = json['text'],
19
        x1 = json['x1'],
20
        y1 = json['y1'],
21
        x2 = json['x2'],
22
        y2 = json['y2'],
23
        x3 = json['x3'],
24
        y3 = json['y3'],
25
        x4 = json['x4'],
26
        y4 = json['y4'];
27

          
28
  Map<String, dynamic> toJson() => {
29
        'format': format,
30
        'text': text,
31
        'x1': x1,
32
        'y1': y1,
33
        'x2': x2,
34
        'y2': y2,
35
        'x3': x3,
36
        'y3': y3,
37
        'x4': x4,
38
        'y4': y4,
39
      };
40
}



Create methods decodeFile() and decodeImageBuffer() respectively for picture and video stream scenarios:

Java
 




xxxxxxxxxx
1
22


 
1
List<BarcodeResult> _convertResults(List<Map<dynamic, dynamic>> ret) {
2
    return ret.map((data) => BarcodeResult.fromJson(data)).toList();
3
}
4

          
5
Future<List<BarcodeResult>> decodeFile(String filename) async {
6
    List<Map<dynamic, dynamic>> ret = List<Map<dynamic, dynamic>>.from(
7
        await _channel.invokeMethod('decodeFile', {'filename': filename}));
8
    return _convertResults(ret);
9
}
10

          
11
Future<List<BarcodeResult>> decodeImageBuffer(
12
      Uint8List bytes, int width, int height, int stride, int format) async {
13
    List<Map<dynamic, dynamic>> ret = List<Map<dynamic, dynamic>>.from(
14
        await _channel.invokeMethod('decodeImageBuffer', {
15
      'bytes': bytes,
16
      'width': width,
17
      'height': height,
18
      'stride': stride,
19
      'format': format
20
    }));
21
    return _convertResults(ret);
22
}



The _convertResults() function is used to convert List<Map<dynamic, dynamic>> type to <List<BarcodeResult>> type.

Java Code

When invoking Flutter API, the Android onMethodCall() function will be triggered:

Java
 




xxxxxxxxxx
1
44


 
1
@Override
2
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
3
    switch (call.method) {
4
        case "getPlatformVersion":
5
            result.success("Android " + android.os.Build.VERSION.RELEASE);
6
            break;
7
        case "decodeFile": {
8
            final String filename = call.argument("filename");
9
            List<Map<String, Object>> results = mBarcodeManager.decodeFile(filename);
10
            result.success(results);
11
        }
12
        break;
13
        case "decodeFileBytes": {
14
            final byte[] bytes = call.argument("bytes");
15
            List<Map<String, Object>> results = mBarcodeManager.decodeFileBytes(bytes);
16
            result.success(results);
17
        }
18
        break;
19
        case "decodeImageBuffer": {
20
            final byte[] bytes = call.argument("bytes");
21
            final int width = call.argument("width");
22
            final int height = call.argument("height");
23
            final int stride = call.argument("stride");
24
            final int format = call.argument("format");
25
            final Result r = result;
26
            mExecutor.execute(new Runnable() {
27
                @Override
28
                public void run() {
29
                    final List<Map<String, Object>> results = mBarcodeManager.decodeImageBuffer(bytes, width, height, stride, format);
30
                    mHandler.post(new Runnable() {
31
                        @Override
32
                        public void run() {
33
                            r.success(results);
34
                        }
35
                    });
36

          
37
                }
38
            });
39
        }
40
        break;
41
        default:
42
            result.notImplemented();
43
    }
44
}



Here are the basic steps for platform-specific code:

  1. Extract the arguments from the Dart framework.
  2. Process the image data.
  3. Return the results.

The decodeImageBuffer method is designed for camera stream. To avoid blocking the main thread, I use SingleThreadExectuor to deal with the CPU-intensive work in a worker thread.

Publishing Flutter Barcode SDK Plugin to Pub.dev

Prior to publishing the plugin, you’d better pass analysis by running the command:

flutter pub publish --dry-run


If there is no error, you can publish the package to pub.dev:

flutter pub publish


I have successfully published the Flutter barcode SDK to https://pub.dev/packages/flutter_barcode_sdk.

Flutter Barcode Scanner

Once the plugin is done, it is time to build a barcode scanner app with a few lines of Dart code.

First, I add the Flutter camera plugin and flutter_barcode_sdk to the pubspec.yaml file:

Java
 




xxxxxxxxxx
1


 
1
dependencies:
2
  camera:
3
  flutter_barcode_sdk:



Then, initialize the camera and barcode reader objects in main.dart:

Java
 




xxxxxxxxxx
1
23


 
1
CameraController _controller;
2
Future<void> _initializeControllerFuture;
3
FlutterBarcodeSdk _barcodeReader;
4
bool _isScanAvailable = true;
5
bool _isScanRunning = false;
6
String _barcodeResults = '';
7
String _buttonText = 'Start Video Scan';
8

          
9
@override
10
void initState() {
11
  super.initState();
12

          
13
  _controller = CameraController(
14
    widget.camera,
15
    ResolutionPreset.medium,
16
  );
17

          
18
  _initializeControllerFuture = _controller.initialize();
19
  _initializeControllerFuture.then((_) {
20
    setState(() {});
21
  });
22
  _barcodeReader = FlutterBarcodeSdk();
23
}



The app consists of a camera view, a text widget and two button widgets:

Java
 




xxxxxxxxxx
1
45


 
1
@override
2
Widget build(BuildContext context) {
3
  return Column(children: [
4
    Expanded(child: getCameraWidget()),
5
    Container(
6
      height: 100,
7
      child: Row(children: <Widget>[
8
        Text(
9
          _barcodeResults,
10
          style: TextStyle(fontSize: 14, color: Colors.white),
11
        )
12
      ]),
13
    ),
14
    Container(
15
      height: 100,
16
      child: Row(
17
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
18
          children: <Widget>[
19
            MaterialButton(
20
                child: Text(_buttonText),
21
                textColor: Colors.white,
22
                color: Colors.blue,
23
                onPressed: () async {
24
                  try {
25
                    // Ensure that the camera is initialized.
26
                    await _initializeControllerFuture;
27

          
28
                    videoScan();
29
                    // pictureScan();
30
                  } catch (e) {
31
                    // If an error occurs, log the error to the console.
32
                    print(e);
33
                  }
34
                }),
35
            MaterialButton(
36
                child: Text("Picture Scan"),
37
                textColor: Colors.white,
38
                color: Colors.blue,
39
                onPressed: () async {
40
                  pictureScan();
41
                })
42
          ]),
43
    ),
44
  ]);
45
}



In the videoScan() function, I invoke startImageStream() to continuously get the latest video frame and call the barcode decoding API:

Java
 




xxxxxxxxxx
1
56


 
1
void videoScan() async {
2
  if (!_isScanRunning) {
3
    setState(() {
4
      _buttonText = 'Stop Video Scan';
5
    });
6
    _isScanRunning = true;
7
    await _controller.startImageStream((CameraImage availableImage) async {
8
      assert(defaultTargetPlatform == TargetPlatform.android ||
9
          defaultTargetPlatform == TargetPlatform.iOS);
10
      int format = FlutterBarcodeSdk.IF_UNKNOWN;
11

          
12
      switch (availableImage.format.group) {
13
        case ImageFormatGroup.yuv420:
14
          format = FlutterBarcodeSdk.IF_YUV420;
15
          break;
16
        case ImageFormatGroup.bgra8888:
17
          format = FlutterBarcodeSdk.IF_BRGA8888;
18
          break;
19
        default:
20
          format = FlutterBarcodeSdk.IF_UNKNOWN;
21
      }
22

          
23
      if (!_isScanAvailable) {
24
        return;
25
      }
26

          
27
      _isScanAvailable = false;
28

          
29
      _barcodeReader
30
          .decodeImageBuffer(
31
              availableImage.planes[0].bytes,
32
              availableImage.width,
33
              availableImage.height,
34
              availableImage.planes[0].bytesPerRow,
35
              format)
36
          .then((results) {
37
        if (_isScanRunning) {
38
          setState(() {
39
            _barcodeResults = getBarcodeResults(results);
40
          });
41
        }
42

          
43
        _isScanAvailable = true;
44
      }).catchError((error) {
45
        _isScanAvailable = false;
46
      });
47
    });
48
  } else {
49
    setState(() {
50
      _buttonText = 'Start Video Scan';
51
      _barcodeResults = '';
52
    });
53
    _isScanRunning = false;
54
    await _controller.stopImageStream();
55
  }
56
}



The pictureScan() function reads barcode from an image and show the image and results on a picture screen:

Java
 




xxxxxxxxxx
1
13


 
1
void pictureScan() async {
2
  final image = await _controller.takePicture();
3
  List<BarcodeResult> results = await _barcodeReader.decodeFile(image?.path);
4

          
5
  Navigator.push(
6
    context,
7
    MaterialPageRoute(
8
      builder: (context) => DisplayPictureScreen(
9
          imagePath: image?.path,
10
          barcodeResults: getBarcodeResults(results)),
11
    ),
12
  );
13
}



Finally, I can build and run the app:

flutter run


A test for recognizing the 1D barcode and QR code on the Raspberry Pi packing box.

Video Barcode Scan

flutter barcode scanner

Picture Barcode Scan

Flutter barcode reader

Pre-requisites

iOS, Web, and Windows.

Source Code

https://github.com/yushulx/flutter_barcode_sdk

Barcode Flutter (software) Barcode Scanner (application) Scratch (programming language)

Published at DZone with permission of Xiao Ling. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Developing a Barcode Reader To Make Life Easier
  • How to Create a Live Barcode Scanner Using the Webcam in JavaScript
  • Performance Optimization Techniques in Flutter 3.41 for Mobile App Development
  • Publishing Flutter Packages to JFrog Artifactory

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook