Appearance
Usage Guide
Quick Start
Start the ScanActivity and process the results:
kotlin
import com.kinegram.android.scansdk.Scanner
import com.kinegram.android.scansdk.activity.ScanActivity
import com.kinegram.android.scansdk.activity.ScanActivity.Companion.getScanResults
class MainActivity : AppCompatActivity() {
private val resultLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == RESULT_OK) {
val results = result.data?.getScanResults() ?: return@registerForActivityResult
// Process results…
}
}
fun openScanner() {
resultLauncher.launch(Intent(this, ScanActivity::class.java))
}
}kotlin
package com.kinegram.android.scansdk.demo
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle
import android.view.View
import com.kinegram.android.scansdk.Scanner
import com.kinegram.android.scansdk.activity.ScanActivity
import com.kinegram.android.scansdk.activity.ScanActivity.Companion.getScanResults
class MainActivity : Activity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode != SCAN_RESULT || resultCode != RESULT_OK) {
return
}
val results = data?.getScanResults() ?: return
val message = results.joinToString("\n") { result ->
"${result.type}:\n${
when (result.type) {
Scanner.ScanType.Barcode -> "${result.text}\n${result.format}"
Scanner.ScanType.MRZ -> result.mrz?.toString()
Scanner.ScanType.IDL -> result.idl?.toString()
Scanner.ScanType.IDB -> result.idb?.toString()
Scanner.ScanType.VDS -> result.vds?.toString()
Scanner.ScanType.VDSNC -> result.vdsNc?.toString()
Scanner.ScanType.NumberPlate -> result.numberPlate?.toString()
else -> result.text
}
}"
}
AlertDialog.Builder(this)
.setMessage(message)
.create()
.show()
}
override fun onCreate(state: Bundle?) {
super.onCreate(state)
setContentView(R.layout.activity_main)
findViewById<View>(R.id.scan).apply {
setOnClickListener {
startActivityForResult(
Intent(this@MainActivity, ScanActivity::class.java),
SCAN_RESULT
)
}
}
}
companion object {
private const val SCAN_RESULT = 1
}
}Continuous Scanning
By default ScanActivity closes itself as soon as it finds a result. To keep the scanner running and decide yourself whether to continue or stop — for example to show an alert for some number plates but not others — subclass ScanActivity, override onScanResults(), and call resumeScanning() or finishWithResults():
kotlin
class MyScanActivity : ScanActivity() {
override fun onScanResults(results: List<Scanner.ScanResult>) {
val plate = results.firstOrNull { it.type == Scanner.ScanType.NumberPlate }
if (plate != null && shouldAlert(plate)) {
AlertDialog.Builder(this)
.setMessage("Flagged plate: ${plate.numberPlate?.text}")
.setCancelable(false)
.setPositiveButton("Continue") { _, _ -> resumeScanning() }
.setNegativeButton("Stop") { _, _ -> finishWithResults(results) }
.show()
} else {
resumeScanning()
}
}
}Declare your subclass, not ScanActivity itself, in AndroidManifest.xml. Note that the same object may be reported again once scanning resumes if it is still in view — debounce on the fields you care about (e.g. numberPlate.text) if that matters for your use case.
Processing ScanResults
A list of ScanResult objects is returned from the scan activity. Each ScanResult contains the recognized data along with its type, defined by the ScanType enum:
| ScanType | Properties |
|---|---|
Barcode | text, format |
MRZ | mrz |
IDL | idl |
NumberPlate | numberPlate |
IDB | idb |
VDS | vds |
VDSNC | vdsNc |
Custom IDB Profiles
Use Scanner.setIDBProfiles() to set custom IDB profiles before scanning:
kotlin
Scanner.setIDBProfiles(
"["
"{\"tag\":9,\"name\":\"Card Access Number\",\"type\":\"C40STR\"}"
"]",
)Custom VDS Profiles
Use Scanner.setVDSProfiles() to specify custom VDS profiles:
kotlin
Scanner.setVDSProfiles(
"["
"{\"id\":4128,\"features\":["
"{\"tag\":2,\"name\":\"foo\",\"type\":\"UTF8STR\"}"
"]}"
"]"
)The integer key (4128 in this example, which is 0x1020 hexadecimal; JSON does not support hexadecimal numbers) must be the "Document Feature Definition Reference" byte (0x10 in bit 9 to 16) and the "Document Type Category" byte (0x20 in bit 1 to 8). These bytes identify a VDS profile.
Document Feature Types
For each document feature you need to specify a tag, a name, and a type. Possible types are:
| Type | Description |
|---|---|
RAW | Binary data |
UBYTE | Unsigned char |
UINT16LE | Unsigned 16-bit integer little endian |
UINT24LE | Unsigned 24-bit integer little endian |
UINT32LE | Unsigned 32-bit integer little endian |
DATE | Unsigned 24-bit integer big endian read as "MMddyyyy" |
TIMESTAMP | Unix time stamp |
UTF8STR | UTF8 string |
C40STR | C40-encoded string |
C40MRZMRVA | C40-encoded MRVA MRZ |
C40MRZMRVB | C40-encoded MRVB MRZ |
C40MRZTD2 | C40-encoded TD2 MRZ |
C40MRZTD3 | C40-encoded TD3 MRZ |
VDS Verification
To verify a VDS, you need the certificate with which the VDS was signed.
Use Scanner.setCertificates() to specify a list of certificate files before scanning:
kotlin
Scanner.setCertificates(listOf("path/to/certificate.cer"))VDS-NC / IDB Verification
To verify a VDS-NC or IDB barcode, the CSCA (Country Signing Certificate Authority) certificate of the issuing country is required. This certificate can be obtained from the ICAO master list or the BSI master list.
Use Scanner.setCMS() to specify a list of master list files before scanning:
kotlin
Scanner.setCMS(listOf("path/to/masterlist.ml"))