Updated 15 min read By Marvin Frankenfeld

How to Build an Android Document Scanner with Kotlin

This guide shows how to integrate a production-ready document scanner into a native Android app with Kotlin and Docutain SDK 1.9.0.0.

The resulting workflow captures or imports documents, detects their edges, corrects the perspective and prepares the pages for PDF export, OCR or structured data extraction. Processing runs locally on the device; your app decides whether and where a result is stored or transferred.

The examples target Android 16 (API level 36) and use the current Activity Result API. If you only need the minimum integration, you can complete the setup and scanner sections first and add OCR or data extraction later.

Minimum version
Android 6.0 / API 23
Example target
Android 16 / API 36
Processing
100% local and offline
Outputs
PDF, JPG, OCR and JSON
Jump to setup

What you will build

A mobile document scanner is more than a camera screen. A reliable scan flow needs to guide the user, identify the document in the camera frame, capture it at the right moment, correct its perspective and create a consistent output for downstream processing.

The workflow in this tutorial is:

  1. Launch Docutain's ready-to-use scan UI from your activity.
  2. Capture one or multiple pages, or import existing images.
  3. Let the user review, crop, rotate, filter and arrange pages.
  4. Export a searchable PDF or page images.
  5. Optionally read the full OCR text or extract structured document data as JSON.

Docutain performs these steps offline. This is useful when documents contain personal, financial or business data and the application must remain functional without a network connection.

Real-world example

From camera image to usable document

A scanner integration must handle oblique capture angles, creases in the paper and uneven lighting. Docutain detects the document boundaries and prepares the page for export, OCR or data extraction.

Creased demo invoice photographed at an oblique angle on a desk
Before correctionCreased, captured at an angle and unevenly illuminated
Perspective-corrected and cropped demo invoice
After correctionDeskewed, cropped and prepared for downstream processing

Prerequisites for Android 16

Component Recommended setup for this guide
Language Kotlin
Minimum Android version Android 6.0 / API level 23
Compile and target SDK API level 36 for Android 16
Android Gradle Plugin A current API-36-compatible version; Docutain requires at least 8.0.2
Test hardware A physical Android device with a rear-facing camera

Set compileSdk = 36 and targetSdk = 36 when preparing the app for Android 16. Google Play generally requires new apps and app updates to target API level 36 from August 31, 2026; consult the official target API requirements for form-factor exceptions and later changes.

Add Docutain SDK 1.9.0.0

1. Add Maven Central

Make sure mavenCentral() is available in settings.gradle:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

2. Add the SDK modules

The UI module contains the document scanner. Add the DataExtraction module when the app also needs OCR or structured data extraction.

def docutainSdkVersion = '1.9.0.0'

// Document Scanner UI
implementation("de.docutain:Docutain-SDK-UI:$docutainSdkVersion")

// Optional: OCR and structured data extraction
implementation("de.docutain:Docutain-SDK-DataExtraction:$docutainSdkVersion")

If you use OCR or data extraction, also set android.enableJetifier=true in gradle.properties. Before updating this article's pinned version, check the Android SDK changelog for migration notes.

3. Check the manifest

The merged application manifest must contain camera access for camera-based scanning:

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

<!-- Use required="false" if the app also supports file-only import. -->
<uses-feature
    android:name="android.hardware.camera"
    android:required="false" />

High-resolution document images require memory. Docutain's Android setup therefore recommends enabling a large heap for the host application:

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

Initialize the SDK

Initialize Docutain before exposing scanner functionality. A production license key is bound to the app's applicationId. For a first evaluation, the SDK can run for 60 seconds without a key; an extended trial license is available for realistic testing.

import de.docutain.sdk.DocutainSDK

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val initialized = DocutainSDK.initSDK(
            this.application,
            "<YOUR-LICENSE-KEY>"
        )

        if (!initialized) {
            val error = DocutainSDK.getLastError()
            // Log the error and disable actions that require the SDK.
        }
    }
}

Do not let the user start a scan after initialization failed. For diagnostics, the SDK log can be retrieved through the Docutain Logger API and shared with support when required.

Start the document scanner

Register the result contract once as a property of the activity or fragment. Launch it with a new DocumentScannerConfiguration when the user taps the scan button.

import de.docutain.sdk.ui.DocumentScannerConfiguration
import de.docutain.sdk.ui.ScanResult

private val documentScanResult = registerForActivityResult(ScanResult()) { success ->
    if (success) {
        // The scanned pages are now available through Docutain's Document APIs.
        // Continue with PDF, image, OCR or data extraction.
    } else {
        // The user canceled the scan process.
    }
}

private fun startDocumentScan() {
    val configuration = DocumentScannerConfiguration()
    documentScanResult.launch(configuration)
}

The default configuration already supports automatic capture, multi-page documents and page editing. Start with the defaults, validate the complete workflow and customize only what the use case requires.

Configure scan and import

The following example enables a final page confirmation and lets the user retake a page:

private fun startConfiguredScan() {
    val configuration = DocumentScannerConfiguration().apply {
        autoCapture = true
        multiPage = true
        confirmPages = true
        pageEditConfig.allowPageRetake = true
    }

    documentScanResult.launch(configuration)
}

Other useful configuration decisions include:

  • Automatic or manual capture: autoCapture controls camera triggering; allowCaptureModeSetting can expose a user-facing switch.
  • Single or multi-page: set multiPage = false when the process accepts exactly one page.
  • Review workflow: page-edit settings control cropping, filters, rotation, arrangement, retake, add and delete actions.
  • Camera and import: the source can be camera, one or multiple gallery images, image files supplied by the app, or camera plus an import button.
  • Branding: colors, icons, button labels and scanner texts can be adapted to the host app.
  • Guidance: onboarding and Scan Tips are optional and can use default or custom content.

See the current Document Scan configuration reference before relying on a specific default in a long-lived application.

Create PDF, images, OCR and structured JSON

Create a PDF

After a successful scan, Document.writePDF() creates a searchable or non-searchable PDF depending on the selected option and available OCR module. PDF creation can take time for long documents, so run it outside the UI thread in production code.

import de.docutain.sdk.Document
import de.docutain.sdk.DocutainSDK
import java.io.File

val pdfFile = Document.writePDF(File(filesDir, "scanned-document.pdf"))
if (pdfFile == null) {
    val error = DocutainSDK.getLastError()
}

Page format and maximum file size can also be specified. Compression trades output quality and processing time for a smaller file.

Export page images

Use Document.pageCount() and Document.writeImage() to export JPG files. Page indexes are 1-based. Alternatively, retrieve pages as Bitmap or ByteArray and choose between filtered, cropped-only and original sources.

val pageCount = Document.pageCount()
for (i in 1..pageCount) {
    val file = File(filesDir, "Image$i.jpg")
    val fileReturn = Document.writeImage(i, file)
}

Read OCR text

import de.docutain.sdk.dataextraction.DocumentDataReader

val completeText = DocumentDataReader.getText()
val firstPageText = DocumentDataReader.getText(1)

Extract structured document data

val jsonData = DocumentDataReader.analyze()

The returned JSON can contain fields such as addresses, dates, amounts, invoice identifiers and payment references. Optional analysis flags are available for BIC, payment state and SEPA creditor. Configure these before scanning and validate extracted values against your business rules before automated downstream processing.

Android 16 test checklist

Updating compileSdk and targetSdk is only the first step. Run the scanner and the surrounding host-app flow on Android 16 and include these checks:

  • Camera permission: first request, denial, later approval and revocation.
  • Edge-to-edge layouts: no controls hidden behind status or navigation bars.
  • Predictive Back: canceling or leaving scanner screens behaves as expected.
  • Large screens and rotation: activity content remains usable on tablets, foldables and resizable windows.
  • 16-KB memory pages: test current arm64 devices or emulators with the latest SDK version.
  • Process recreation: repeat the flow after backgrounding or recreating the host activity.
  • Real documents: test different paper sizes, lighting, backgrounds, page counts and low-end devices.
  • Result handling: verify empty, canceled and failed states before uploading or persisting a document.

Review both the changes affecting all apps and the changes for apps targeting API 36 as part of release testing.

Common integration mistakes

  • Using UI and OCR APIs without adding the correct SDK modules.
  • Allowing scan actions after DocutainSDK.initSDK() returned false.
  • Performing PDF creation or extensive result processing on the main thread.
  • Testing the camera workflow only on an emulator.
  • Assuming OCR or extracted fields are always complete without application-level validation.
  • Copying a production license key to an app with a different applicationId.

Official resources

Technical sources last checked on August 29, 2026.

FREQUENTLY ASKED QUESTIONS

Android document scanner integration





Contact us and receive your quote

Our pricing is tailored to your use case. Let our colleague Harry Beck know how we can help and receive your quote.




Information about how we process your details is available in our Privacy Policy.