Flutter tutorial – How to integrate our scanning functionalities

In our most recent article, we already praised the versatility and ease of use of Flutter. To get you even more excited, you should check out this small tutorial for yourself. You’ll be surprised how easy it is to add complex functionality like our Scanner SDK for Flutter with a few lines of code. Let’s go …

app store

Getting started

Requirements
For Android apps
For iOS apps


You can use Android Studio as an IDE for developing Flutter apps. Also, there are Flutter IDE plugins available for VS Code and IntelliJ IDEA. In this tutorial, we will use the Flutter CLI (Command Line Interface) tools, as this works pretty well independently of any IDE plugins.

Once you have installed Flutter, you can run the command flutter doctor to verify that all required tools are correctly setup.

Create a “Hello World” Flutter app

$ flutter create --androidx my_awesome_flutter_app

This command generates a simple Flutter scaffold project for Android and iOS.

Please note the option –androidx, which generates the Android project using the new AndroidX libraries. It’s not only required to use the latest version of the Scanbot Android SDK but also highly recommended for every new Android Flutter project.

(If you need to migrate your Flutter project to AndroidX, please check out the respective Flutter docs “AndroidX Migration”).

Test run

Connect a mobile device via USB and run the app.

Android

$ cd my_awesome_flutter_app/
$ flutter run -d <DEVICE_ID>

You can get the IDs of all connected devices via flutter devices.

iOS

Open the Xcode workspace ios/Runner.xcworkspace and adjust the Signing / Developer Account settings in Xcode IDE. Then build and run the app in Xcode.

Both on Android and iOS you should see the same “Hello World” app which shows a simple UI with a button and label widgets as well as the functionality to increment a counter.‍

Add the Scanbot SDK Flutter plugin

As the next step, we will add the Scanbot Scanner SDK for Flutter Plugin, which is provided as a public Flutter package. Flutter plugins are available as packages and provide access to native system APIs like camera, network, battery status, etc. as well as 3rd-party platform SDKs like, for example, Firebase.

There are a lot of packages hosted on the official repository pub.dev, which is an equivalent to npmjs.org for Node packages or nuget.org for Xamarin packages. For more details about Flutter packages, refer to the Flutter docs “Using packages.”

So, let’s add the scanbot_sdk package to our project. Just open the file pubspec.yaml and define the package under dependencies:

dependencies:
  scanbot_sdk: ^1.0.0

After adding new packages you need to fetch and install them. For that we return again to the Flutter CLI and run the command:

$ flutter pub get

Android tunings

To support the latest Scanbot Android SDK we have to adjust some Gradle settings.

As the Flutter generated Android project is based on an older Kotlin version 1.2.x we need to raise this version to 1.3.x. In the top-level android/build.gradle file:

buildscript {
    ext.kotlin_version = '1.3.41'
    ...
}

In the app-level android/app/build.gradle file enable multidex and add the following packagingOptions:

android {
    ...
    defaultConfig {
      applicationId "com.example.myAwesomeFlutterApp"
      ...
      multiDexEnabled true
    }

    packagingOptions {
        pickFirst 'META-INF/atomicfu.kotlin_module'
        pickFirst 'META-INF/proguard/coroutines.pro'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }
}

In the android/app/src/main/AndroidManifest.xml file add the CAMERA permission:

<manifest ...>
  <uses-permission android:name="android.permission.CAMERA" />
  ...
</manifest>

iOS setup

Specify a global platform version in the ios/Podfile file, like:

platform :ios, '9.0'

Then install the Pods by running:

$ cd ios/
$ pod install


And finally add the required NSCameraUsageDescription property in Xcode in the Info settings tab of the project (aka. Info.plist file):

NSCameraUsageDescription “Privacy – Camera Usage Description”

Scanbot SDK:
Unlimited scanning at a fixed price

Your reliable data capture solution for mobile and web app integration.


Supports all common platforms and frameworks.

It’s coding time

Now, let’s write some Dart code! We are going to adjust the lib/main.dart file, which is the entry point of your Flutter app.

Import Scanbot SDK classes

Add the following imports of some Scanbot SDK packages and Flutter UI widgets we will use:

import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:scanbot_sdk/common_data.dart';
import 'package:scanbot_sdk/document_scan_data.dart';
import 'package:scanbot_sdk/scanbot_sdk.dart';
import 'package:scanbot_sdk/scanbot_sdk_models.dart';
import 'package:scanbot_sdk/scanbot_sdk_ui.dart';

Initialize the Scanbot SDK

The Scanner SDK for Flutter must be initialized before usage. Use the ScanbotSdk.initScanbotSdk(config) SDK API method for that. We initialize the Scanbot SDK when the main app widget is built:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    ScanbotSdk.initScanbotSdk(ScanbotSdkConfig(
      loggingEnabled: true,
      licenseKey: "", // see the license key notes below!
    ));

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

For the full API reference of the Scanbot SDK Flutter Plugin please check out the documentation.‍

Integrate the document scanner UI

The Scanbot Scanner SDK for Flutter Plugin provides a scanner UI for document scanning. The Document Scanner is a complete and ready-to-use screen component and can be easily integrated with just a few lines of code using the API method ScanbotSdkUi.startDocumentScanner(config).

Let’s put the SDK call in a simple function named scanDocument() so we can bind it to a button:

class _MyHomePageState extends State<MyHomePage> {

  void scanDocument() async {
    var config = DocumentScannerConfiguration(
      multiPageEnabled: false,
      bottomBarBackgroundColor: Colors.blueAccent,
      cancelButtonTitle: "Cancel",
      // see further configs ...
    );
    var result = await ScanbotSdkUi.startDocumentScanner(config);

    if (result.operationResult == OperationResult.SUCCESS) {
      // get and use the scanned images as pages: result.pages[n] ...
      displayPageImage(result.pages[0]);
    }
  }

  ...
}


Btw: we really like and recommend the async/await pattern in Dart, which is also known from other languages like C#, TypeScript, JavaScript, etc.

Now add a Flutter widget CupertinoButton and bind our scanDocument() method as onPressed event:

CupertinoButton(
  child: Text("Scan a Document"),
  onPressed: scanDocument,
),

With the DocumentScannerConfiguration, you can pass config parameters on customizing colors, text resources, and some feature behavior of the Document Scanner. See the API docs for more details.

As a result, the Document Scanner returns an array of Page objects which contain the scanned document and original images. A document image is the cropped and perspective corrected image (hi-res), while the original image is the unprocessed image (hi-res). All models are stored as JPG files by default and represented as file URIs (file:///…). Furthermore, a Page object provides preview images (low-res), which should be used as thumbnails for displaying.

For simplicity, in this example, we have disabled the multipage feature of the Document Scanner via the config parameter multiPageEnabled: false. So the Scanner UI will automatically close after one single scan, and we can use the first Page element from the array result.pages[0] to display its cropped document image.

Display the scanned image

Use the JPG file URI of a Page object page.documentPreviewImageFileUri to show a preview image. For that, we add another Flutter widget Image and store an instance as a variable named currentPreviewImage. To display the last scanned Page image we implement a simple method displayPageImage(page) which updates the state of the currentPreviewImage widget:

class _MyHomePageState extends State<MyHomePage> {

  Image currentPreviewImage;

  void scanDocument() async { ... }

  void displayPageImage(Page page) {
    setState(() {
      currentPreviewImage = Image.file(File.fromUri(page.documentPreviewImageFileUri), width: 300, height: 300);
    });
  }

  ....
}

And finally render the currentPreviewImage widget conditionally right below our CupertinoButton:

...
CupertinoButton(
  child: Text("Scan a Document"),
  onPressed: scanDocument,
),
if (currentPreviewImage != null) ... [
  Text("Document image:"),
  currentPreviewImage,
],

Complete example projects

To get off to a flying start check out the following example projects on GitHub:

– small example project for this tutorial: https://github.com/doo/my_awesome_flutter_app

– full example project: https://github.com/doo/scanbot-sdk-example-flutter
It demonstrates the integration of all API methods of the Scanbot SDK Flutter Plugin, such as Cropping UI, Image Filtering, PDF and TIFF Rendering, Optical Character Recognition, Barcode, and QR Code Scanning, MRZ Scanner (Machine Readable Zones), and EHIC Scanning (European Health Insurance Card).

Scanbot SDK (trial) license key

Please note: The Scanbot SDK will run without a license key for one minute per session! After the trial period is over, all Scanbot Scanner SDK for Flutter functions, as well as the UI components, will stop working or may be terminated.

You can get an unrestricted, no-strings-attached 7-day trial license for free.

As the Scanbot SDK license key is bound to an App Identifier (aka. Application ID on Android and Bundle Identifier on iOS), you will have to use the default generated App Identifier com.example.myAwesomeFlutterApp of this tutorial app. Of course, you can also use the ID of your app to get a trial license. Please also note that app IDs are case sensitive!

To request one license key for both platforms, Android and iOS, for this tutorial app, make sure the app IDs are the same. Typically you will need to change the app ID of the default generated Android project from com.example.my_awesome_flutter_app to com.example.myAwesomeFlutterApp, as Flutter makes different IDs for those two platforms.

Where to find the app identifier:

  • For Android see applicationId … in the android/app/build.gradle file.
  • For iOS see Bundle Identifier in the General settings tab in Xcode IDE.

💡 You can also follow along our tutorial on YouTube!

💡 Did you have trouble with this tutorial?

We offer free integration support for the implementation and testing of the Scanbot SDK. If you encounter technical issues or need advice on choosing the appropriate framework or features, join our Slack or MS Teams or send us an email to receive your free support.

Developers, ready to get started?

Adding our free trial to your app is easy. Download the Scanbot SDK now and discover the power of mobile data capture