Android app development tutorial – How to integrate our scanning functionalities

November 10, 2021

This article will show you how fast and easy it is to create an Android app with Scanbot SDK integrated. Let's go...

Getting started

Requirements:

Android Studio is the most commonly used IDE for developing Android applications. Alternatively, you could use IntelliJ IDEA. In this tutorial, we will only use standard Android SDK features – and the Scanbot SDK.

Create a “Hello World” Android app

In Android Studio, create a new project with an empty Activity. To do that, go to File -> New -> New Project. Then, select the Empty Activity template – we won’t need any complex UI or special features. 

On the next screen, choose “io.example.myapplication” as the package name, then press “Finish”. 

Android Studio will now generate a simple Android project for you.

Note: Make sure that the option “Use legacy android.support.libraries” is unchecked and that Android Studio generates the Android project using the new AndroidX libraries. 

Currently, the minimal version of Android SDK supported by Scanbot SDK is 5.0 (21 API Level). Select a larger value if you want to restrict users with outdated OS versions from installing your app.

Test run

First, connect a mobile device via USB (ADB debugging needs to be enabled). Alternatively, you can create and use an emulated device via AVD Manager in Android Studio. However, a real device is recommended because of the camera functionality.

Select your device or emulator in the navigation bar and press the Run button. 


You should now see an empty app with a simple "Hello World!" label running on your device.

Add the Scanbot SDK dependencies

Next, we will add the Scanbot Scanner SDK for Android dependency, which comes as a set of Gradle modules. Gradle dependencies let you quickly integrate and update third-party libraries that simplify access to native system APIs like camera, network or battery status as well as third-party platform SDKs like Firebase.

For more details about Gradle dependencies, refer to the Android docs “Build dependencies.”

So, let’s add the Scanbot SDK modules to our project. 

Gradle allows you to pull external dependencies from different repositories. The Scanbot SDK modules are stored on our Nexus repository, and so we need to add it to the list of repositories in the project’s settings.gradle file.

Add the Scanbot repository under the mavenCentral and google repositories:


dependencyResolutionManagement {
   repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
   repositories {
       google()
       mavenCentral()
       maven { url 'https://nexus.scanbot.io/nexus/content/repositories/releases/' }
}

We also need to add the Scanbot SDK dependency to the app module of the application. Depending on the feature set we want, different Gradle dependencies are required. 

In this tutorial, we will only use the Document Scanning feature, which means adding the dependency module "io.scanbot:sdk-package-1". 

For this, open the build.gradle file of the app module.


Add the following line to the file: 


implementation "io.scanbot:sdk-package-1:1.87.1"

1.87.1 is the version of the Scanbot SDK for Android we use in this tutorial. You can find the latest version in our changelog.

The Scanbot SDK also provides Ready-to-Use UI (RTU UI) components – Activities that make integrating the scanning features very easy. To use those RTU UI components, also add the following Gradle dependency:


implementation "io.scanbot:sdk-package-ui:1.87.1" 


Don’t forget to sync your project every time you add dependencies 🙂 

To learn more about other features of the SDK and how to set up each component, please refer to our documentation.


Camera permission and further adjustments

In the app/src/main/AndroidManifest.xml file, add the CAMERA permission and declare that the app uses this feature by adding the following:


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


Since our application will work with high-resolution images, we strongly recommend adding the property android:largeHeap="true" to the <application> element of the AndroidManifest.xml file, especially for Android <= 7.x:


<application
  android:largeHeap="true"
  ...>


Processing hi-res images is a memory-intensive task, and this property will ensure your app is allocated enough heap to avoid OutOfMemoryError exceptions.

It’s coding time

Now, let’s write some Kotlin code to put the SDK features to use. 

Initialize the Scanbot SDK

Scanbot SDK needs to be initialized to work properly. For that, we will use the class ScanbotSDKInitializer. The simplest way of doing that is to add it to our Application class, which is the main entry point of an Android application. 

Let’s add a new class <codefont>ExampleApplication<codefont> (New -> Kotlin class) and implement it as follows:


package io.example.myapplication

import android.app.Application
import io.scanbot.sdk.ScanbotSDKInitializer

class ExampleApplication : Application() {
   override fun onCreate() {
       super.onCreate()

       ScanbotSDKInitializer()
           .license(this, LICENSE_KEY) // Please add a valid trial license key here. See the notes below!
           .initialize(this)
   }
}

Now we declare this class in our AndroidManifest.xml:


<application
   android:largeHeap="true"
    android:name=".ExampleApplication"
   ..>
   

Done! Now, the Scanbot SDK will be initialized immediately after the user opens the app. 

Next up: Quickly adding a UI that lets us actually scan something with our new app.

Integrate the Document Scanner UI

As mentioned above, the Scanbot Scanner SDK for Android provides a ready-to-use UI component for document scanning. We can easily integrate this screen component with just a few lines of code. We will use the class DocumentScannerActivity and define our desired configuration with the DocumentScannerConfiguration class.

First, let’s wrap the SDK Activity call into a simple function named scanDocument() – we will bind it to a button later – and add it to our MainActivity class:


class MainActivity : AppCompatActivity() {
   ...

   private fun startDocument() {
       val configuration = DocumentScannerConfiguration()
       configuration.setTopBarBackgroundColor(Color.RED)
       // It is possible to customize the behavior and appearance of the SDK screen
       val docIntent = DocumentScannerActivity.newIntent(this, configuration)
       startActivityForResult(docIntent, DOCUMENT_SCANNER_ACTIVITY_REQUEST_CODE)
   }

   companion object {
       const val DOCUMENT_SCANNER_ACTIVITY_REQUEST_CODE = 100
   }
}

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

Now let's add a button to the layout of our MainActivity. For simplicity’s sake, we will also replace the ConstraintLayout with LinearLayout

Change src/main/res/layout/activity_main.xml to look like this:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/start_scanner_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:text="Start Scanner"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

</LinearLayout>

Next, we will bind our scanDocument() method as an onClickListener event to the button we just created in the onCreate method of our MainActivity class:


override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        findViewById<Button>(R.id.start_scanner_button).setOnClickListener { 
            startDocument()
        }
    }
    

Let’s run the app and see how the scanning UI looks and try to scan a document. 

During the first run, the application will ask for the camera permission it needs to perform a scan. Our RTU UI components handle camera permissions automatically, so you don’t need to worry about it.

Yay! The Document Scanner screen has opened and detects the contour of the document. We can also see that the  toolbar color is now  red, which we set in the configuration. 

Note: To keep things simple, we didn’t enable the multipage feature of the Document Scanner (see the config parameter setMultiPageEnabled, which is false by default). This means that the scanner UI will automatically close after a single scan. Next, we will pull the first Page element from the result array to display the cropped document image.

Let’s proceed!

Process and display the scanned image

After scanning, the Document Scanner Activity returns an array of Page objects. These contain all information about the scanned document. 

As usual in Android development, we need to override the onActivityResult method in the calling Activity to access its results.

First, we make sure that the call is made from our DocumentScannerActivity by checking <codefont>requestCode<codefont> and <codefont>resultCode<codefont>. Then, to access the pages themselves, we need to use the <codefont>SNAPPED_PAGE_EXTRA<codefont> key. In this example, like we said earlier, we are only interested in the first element of the array. We will process the page in the processPagePreview method later.


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == DOCUMENT_SCANNER_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
            val snappedPagesExtra = data?.getParcelableArrayExtra(DocumentScannerActivity.SNAPPED_PAGE_EXTRA)
            snappedPagesExtra?.get(0)?.let { page ->
                processPagePreview(page as Page)
            }
        }
    }

    private fun processPagePreview(page: Page) {
        // We will implement it later
    }
    

To access the image contained in the Page object, we need to use the PageFileStorage class. An instance of it can be created by calling the <codefont>createPageFileStorage()<codefont> in the <codefont>ScanbotSDK<codefont> class. The most convenient place to do this is our onCreate method and saving it as a private property pageFileStorage .


class MainActivity : AppCompatActivity() {
    private lateinit var pageFileStorage: PageFileStorage

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        pageFileStorage = ScanbotSDK(this).createPageFileStorage()
    }
    

To show a preview, we will add an ImageView widget to our layout. The complete layout of our MainActivity now looks like this:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/start_scanner_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:text="Start Scanner"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

   <ImageView
       android:id="@+id/page_preview"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1" />
</LinearLayout>


To actually show the image, let’s implement a <codefont>processPagePreview<codefont> method. We can take the image from the pageFileStorage by a pageId. Alternatively, we could access the file by URI using the getImageURI method. 

In real applications, there would be more efficient ways of loading images from disk (Glide or Picasso libraries, for example).


private fun processPagePreview(page: Page) {
        val imageType = PageFileStorage.PageFileType.DOCUMENT
        val filteredPreviewImage = pageFileStorage.getImage(page.pageId, imageType)
        val previewWidget = findViewById<ImageView>(R.id.page_preview)
        previewWidget.setImageBitmap(filteredPreviewImage)
    }

A <codefont>DOCUMENT<codefont> image type is the cropped and perspective-corrected image (hi-res), while the <codefont>ORIGINAL<codefont> image is the unprocessed image (hi-res). All images are stored as JPG files by default. It’s also possible to  access preview images (low-res), which should be used as thumbnails and can be displayed by calling <codefont>getPreviewImage<codefont>. See the API docs for more details.


Finally, let’s run our app once more – and the cropped image preview appears in the ImageView after the successful scan. Congratulations

Complete example projects

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

- Ready-to-Use UI example project: https://github.com/doo/scanbot-sdk-example-android/tree/master/ready-to-use-ui-demo

This project demonstrates the integration of all API methods of the Scanbot SDK for Android, 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). If you want more control over how the scanning screen looks, or more flexibility in the implementation, you can use our Classical Components. You can find an example project for these components here:
https://github.com/doo/scanbot-sdk-example-android/tree/master/classical-components-demo

Finally, you can find the app we made in this tutorial here: https://github.com/doo/my_awesome_android_app 

Scanbot SDK (trial) license key

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

You can get an unrestricted, no-strings-attached 30-day trial license for free. Go to the Trial License Form on our website to get yours.

As the Scanbot SDK license key is bound to the Application ID, you will have to use the default generated App Identifier (io.example.myapplication) of this tutorial app. Alternatively, you can use the ID of your app when requesting your trial license. Please note that app IDs are case-sensitive!

Where to find the App Identifier

The application ID is defined in the app/build.gradle file as applicationId property:


android {
    defaultConfig {
        applicationId "io.example.myapplication"
        ...
    }
    ...
}

Happy coding! 👩💻👨💻

If you need any kind of assistance, feel free to contact one of our experts. We'd love to help you out.


Get the Scanbot SDK fact sheet

To access the fact sheet, Scanbot will process and use the information you provide to contact you about our products and to send you the monthly newsletter. You may unsubscribe from these communications at any time. For more information, please review our Privacy Policy.

Ready to try it?

Talk to one of our solutions experts to discover how we can solve your mobile data capture requirements or simply integrate it into your own mobile app or website right now.

Contact our solution experts
Try it

Developers, ready to get started?

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