Skip to main content

Android Integration

This guide will help you integrate the OCR Lite SDK into your Android application.

note

You can find sample project containing complete integration of SDK here.

Installation​

info

OCR Lite SDK is built with the support for minSdk 23 and compiled on JAVA 17.

Prerequisites​

Make sure you are provided with the following required credentials for integration:

S3_BUCKET_ID, S3_ACCESS_KEY, S3_SECRET_KEY and the latest communicated version.

Implementation​

Include AWS maven repository (where the sdk is deployed) at the project's dependency management.

repositories {
...
maven {
url 's3://' + S3_BUCKET_ID
credentials(AwsCredentials) {
accessKey S3_ACCESS_KEY
secretKey S3_SECRET_KEY
}
}
}

Add the following dependency in project's app/build.gradle:

dependencies {
...
implementation 'com.fetchsky.ocrlite:sdk:<version-code>'
}

Launch SDK​

Create an intent and launch OcrActivity. See Initialization Parameters for the full list of supported parameters.

val intent = Intent(this, com.fetchsky.ocrlitesdk.OcrActivity::class.java)
intent.putExtra(OcrCommunication.ParamKey.IDENTITY_NUMBER.value, cnicNumber)
startActivity(intent)

Launch Landscape UI​

The SDK also ships a full-screen landscape scanner, com.fetchsky.ocrlitesdk.OcrLandscapeActivity. To use it, launch OcrLandscapeActivity in place of OcrActivity. It takes the same initialization parameters and posts the same events, so your broadcast receiver does not change.

val intent = Intent(this, com.fetchsky.ocrlitesdk.OcrLandscapeActivity::class.java)
intent.putExtra(OcrCommunication.ParamKey.IDENTITY_NUMBER.value, cnicNumber)
intent.putExtra(OcrCommunication.ParamKey.SCAN_MODE.value, OcrCommunication.ScanMode.FRONT_AND_BACK.value) // Optional
intent.putExtra(OcrCommunication.ParamKey.PRIMARY_COLOR.value, "#007083") // Optional
startActivity(intent)

Your app needs no extra configuration:

  • The activity is declared in the SDK manifest with android:screenOrientation="landscape" and is merged into your app automatically. Your launching activity can stay in portrait.
  • The activity hides the status and navigation bars. The user can swipe from the screen edge to show them temporarily.
  • The camera fills the screen. The area outside the card holder is dimmed; on Android 13 (API 33) and higher it is also blurred.
  • Only the card holder region is classified and saved, so captured images contain the card only.
  • The close button in the top-left corner finishes the activity without posting an event, as in portrait mode.

If you offer both layouts, select the activity class and keep the rest of the launch code shared:

fun launchOcr(landscape: Boolean) {
val activity = if (landscape) {
com.fetchsky.ocrlitesdk.OcrLandscapeActivity::class.java
} else {
com.fetchsky.ocrlitesdk.OcrActivity::class.java
}
val intent = Intent(this, activity)
intent.putExtra(OcrCommunication.ParamKey.IDENTITY_NUMBER.value, cnicNumber)
startActivity(intent)
}

Camera permission​

The SDK declares the CAMERA permission in its manifest (merged into your app) and requests it at runtime when the scan screen opens. You do not need to request it yourself. If the user denies it, the SDK shows a message and the camera stays off; no event is posted.

Receive events​

Receive messages sent from OCR activity and handle them accordingly.

1. Create a Broadcast Receiver​

Events are posted with a standard receiver action:

OCR_RECEIVER_ACTION = "com.fetchsky.ocrlitesdk.OCR_MESSAGE"

Create receiver class:

The constant is available as OcrCommunication.OCR_RECEIVER_ACTION. The event type is in the type extra; the payload is in the remaining Intent extras.

private val ocrMessagesReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == OcrCommunication.OCR_RECEIVER_ACTION) {
val type = intent.getStringExtra("type") ?: return
val payload = intent.extras ?: Bundle()
handleResult(type, payload)
}
}
}

2. Initialize the receiver​

Initialize OCR broadcast receiver at launch:

ContextCompat.registerReceiver(
this,
ocrMessagesReceiver,
IntentFilter(OcrCommunication.OCR_RECEIVER_ACTION),
ContextCompat.RECEIVER_EXPORTED
)

Prefer using ContextCompat receiver registration for lower api level support.

Unregister the receiver when your activity is destroyed:

override fun onDestroy() {
super.onDestroy()
unregisterReceiver(ocrMessagesReceiver)
}

3. Handle results​

info

Event sent from OCR Activity will be one of the defined types listed in Response Events.

Extract the enum of posted event type as follows and handle them as per the need.

fun handleResult(type: String, payload: Bundle) {
val messageTypes = OcrCommunication.PostMessage.entries.associateBy { it.name }
val event = messageTypes[type]
when (event) {
OcrCommunication.PostMessage.FRONT_SUCCESS,
OcrCommunication.PostMessage.BACK_SUCCESS -> {
val imagePath = payload.getString("image")
}
OcrCommunication.PostMessage.OCR_SUCCESS -> {
val identityNumber = payload.getString("identityNumber") // null for "frontOnly"
val frontImage = payload.getString("frontImage")
val backImage = payload.getString("backImage")
val documentType = payload.getString("documentType") // "new" or "old"
val distance = payload.getInt("distance", 1) // 0 = match
}
OcrCommunication.PostMessage.LAUNCH_FAILURE -> { /* identity number missing */ }
OcrCommunication.PostMessage.OCR_FAILURE -> { /* barcode not read; user re-scans back */ }
else -> {}
}
}
note

distance is delivered as an Int. Read it with getInt, not getFloat or getDouble.

If the user closes the scan screen, the activity finishes without posting an event. To detect cancellation, launch the activity with registerForActivityResult(ActivityResultContracts.StartActivityForResult()) and treat a return without a preceding OCR_SUCCESS as cancelled.

Reading extractedData​

On the OCR_SUCCESS event, the SDK includes the parsed CNIC fields — plus a raw entry holding the full unparsed OCR text — as a nested Bundle under the extractedData key. Text recognition and parsing happen inside the SDK. It is empty for old cards, or when no text could be recognized (it never causes a failure). See the extractedData object reference for the full list of fields.

val extracted = payload.getBundle("extractedData") ?: Bundle()

val name = extracted.getString("name") // null if absent
val cnic = extracted.getString("identityNumber")
val raw = extracted.getString("raw") // full unparsed OCR text
// ...other fields: fatherName, dateOfBirth, dateOfIssue, dateOfExpiry, gender, country