Skip to main content
The Android SDK gives you Emirates ID reading and fingerprint capture through a clean Kotlin API. Hardware support is added by including the service packages for the readers and sensors you use.

Download the example app

A single-screen Jetpack Compose app — fill in the config block, build, and run on a device. Walks the full flow: register → pick a method (NFC / card reader / manual) → result.

1. Install

Add the Nexus repository (Configure Nexus) and the dependencies. Include only the service packages whose hardware you support.
dependencies {
    implementation("ae.gov.icp.mbkyc:mbkyc-android:0.7.0")
    implementation("ae.gov.icp.mbkyc:service-common-android:0.4.0")

    // Hardware support — include only what you need (versioned independently)
    implementation("ae.gov.icp.mbkyc:service-smartcard-ccid-android:0.4.0")
    implementation("ae.gov.icp.mbkyc:service-smartcard-nfc-android:0.4.0")
    implementation("ae.gov.icp.mbkyc:service-fingerprint-morpho-android:0.4.0")
    implementation("ae.gov.icp.mbkyc:service-fingerprint-suprema-android:0.1.0")
    implementation("ae.gov.icp.mbkyc:service-fingerprint-zhiang-android:0.1.0")
}
mbkyc-android transitively pulls rustls:rustls-platform-verifier — the native layer calls into it to verify TLS certificates against the Android trust store on every MBKYC.create. It’s an api dependency, so you don’t declare it yourself, but it is served from your mbkyc-maven Nexus repository (group rustls), not Maven Central or Google. Make sure your repository configuration lets the rustls group resolve from Nexus — see Configure Nexus. A missing rustls artifact surfaces at runtime as ClassNotFoundException: org.rustls.platformverifier.CertificateVerifier.

2. Initialize

MBKYC.create() returns an MBKYCResult — call .getOrThrow() if you prefer exceptions. On Android you must pass a Context.
val mbkyc = MBKYC.create(
    context      = applicationContext,
    baseUrl      = "https://api.client.ae",
    apiKeyId     = "key-id",
    // The API secret never enters the SDK. The signer receives the request signing
    // input; route it to the holder of the secret (normally your backend), sign it,
    // and return the signature. See Authentication.
    tokenSigner  = TokenSignerHandler { signingInput -> myBackend.sign(signingInput) },
    logConfig    = LogConfig(logDir = File(filesDir, "logs")),
    timeoutMs    = 30_000,
).getOrThrow()
See Authentication for the token signer.

3. Discover readers & register

val readers = mbkyc.listSmartcardReaders().getOrThrow()
mbkyc.registerDevice("lobby-kiosk").getOrThrow()
The readers you see depend on which service packages you included.

4. Validate

validate(request) dispatches on the request type and whether a fingerprint is attached.
val result = mbkyc.validate(
    EmiratesIdManual(
        idNumber       = "784-XXXX-XXXXXXX-X",
        documentNumber = "...",
        nationality    = "ARE",
        fingerprint    = Fingerprint(
            readerId              = fpReader.id,
            recommendationHandler = handler,
            captureTimeoutMs      = 10_000,
        ),
    )
).getOrThrow()
Pick the request for the document you’re verifying — see Validation methods for when to use each. Card-reading, NFC, and fingerprint capture come from the service AARs and USB-attach wiring described under Hardware support model below; no desktop service is needed.
Manual entry — no hardware required.
EmiratesIdManual(idNumber = "784-XXXX-XXXXXXX-X", documentNumber = "...", nationality = "ARE")
Card read — needs a USB CCID smart card reader.
EmiratesIdCard(readerId = reader.id)
NFC — reads the chip over the device’s built-in NFC (Android only).
EmiratesIdNfc(tag = tag)
+ Fingerprint — attach a fingerprint to any Emirates ID request above to add a biometric match (needs a fingerprint sensor).
EmiratesIdCard(readerId = reader.id, fingerprint = fingerprint)
Full initializers (optional params: dateOfBirth, issueDate, expiryDate, fingerprint, clientReferenceId) are in the Full API reference.

Fingerprint recommendation handler

The SDK calls this mid-flow with the Validation Gateway’s quality-ranked finger list:
val handler = FingerRecommendationHandler { recommended ->
    if (recommended.isNotEmpty()) FingerSelection.Recommended(recommended.first())
    else FingerSelection.Custom(Finger.RightIndex)
}
See Biometrics.

Hardware support model

A hardware integration can live inside your own app or in a separate companion app — whichever fits your deployment. Either way it must carry the same Android signing certificate as your app, because the connection between them is protected at the signature level. There’s nothing else to wire up: the SDK discovers the available readers and sensors and surfaces them through listSmartcardReaders() / listFingerprintReaders().

USB device attach

Android only shows the “Open App when this USB device is connected?” prompt for an activity. To opt in, your launcher activity declares one <intent-filter> for ACTION_USB_DEVICE_ATTACHED plus a <meta-data> pointing at a USB device filter resource. The <usb-device> entries should match the hardware you support (decimal VID/PIDs — Android rejects hex):
Hardware<usb-device>
USB CCID smart card readerclass="11"
IDEMIA (Morpho) MSO 1350vendor-id="8797" (0x225D)
Suprema BioMinivendor-id="5841" (0x16D1)
NEXUS / Zhiangvendor-id="8309" (0x2075)
NFCnot USB — handled via NfcAdapter

Lifecycle

MBKYC is AutoCloseable — always close it:
mbkyc.use { s ->
    s.validate(/* ... */)
}
Build the Fingerprint via its constructor Fingerprint(readerId, recommendationHandler, captureTimeoutMs). On Android, MBKYC.create(context = ...) requires a non-null Context.

Full API reference

Every method returns MBKYCResult<T> (Ok/Err); call .getOrThrow() for exception semantics. Shared types (ReaderInfo, RegistrationStatus, VerificationResult, Finger, FingerSelection) are in Data types.
MethodReturns
MBKYC.create(context, baseUrl, apiKeyId, tokenSigner, logConfig, timeoutMs = 30_000, extraHeaders = emptyMap())MBKYCResult<MBKYC>
listSmartcardReaders()MBKYCResult<List<ReaderInfo>>
listFingerprintReaders()MBKYCResult<List<ReaderInfo>>
registerDevice(name: String)MBKYCResult<Unit>
checkRegistration()MBKYCResult<RegistrationStatus>
validate(request: ValidationRequest)MBKYCResult<VerificationResult>
exportLogs(output: File)MBKYCResult<Unit>
close()— (AutoCloseable)
Validation requests (ValidationRequest):
EmiratesIdCard(readerId: String, cardDipTimeoutMs: Int = 5_000,
               fingerprint: Fingerprint? = null, clientReferenceId: String? = null)
EmiratesIdNfc(tag: Tag, nfcTimeoutMs: Int = 30_000,
              fingerprint: Fingerprint? = null, clientReferenceId: String? = null)   // Android only
EmiratesIdManual(idNumber: String, documentNumber: String, nationality: String,
                 dateOfBirth: String? = null, issueDate: String? = null, expiryDate: String? = null,
                 fingerprint: Fingerprint? = null, clientReferenceId: String? = null)
PassportManual(passportNumber: String, passportType: String, nationality: String,
               dateOfBirth: String? = null, issueDate: String? = null, expiryDate: String? = null,
               clientReferenceId: String? = null)

Fingerprint(readerId: String, recommendationHandler: FingerRecommendationHandler,
            captureTimeoutMs: Int = 10_000, recommendationTimeoutMs: Long = 60_000)
Export logs bundles SDK + service logs into a tar.zst archive:
mbkyc.exportLogs(File(filesDir, "mbkyc-logs.tar.zst")).getOrThrow()
Cancel a validation by cancelling the enclosing coroutine; the result resolves to a CANCELLED error.