> ## Documentation Index
> Fetch the complete documentation index at: https://eurusys-6c0957fa.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Android (Kotlin)

> Integrate the MBKYC SDK into an Android app — install, initialize, register, and validate, including hardware support.

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.

<Card title="Download the example app" icon="download" href="/examples/mbkyc-android-example.zip" cta="mbkyc-android-example.zip">
  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.
</Card>

## 1. Install

Add the Nexus repository ([Configure Nexus](/distribution/configure-nexus)) and the dependencies. Include only the service packages whose hardware you support.

```kotlin theme={null}
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")
}
```

<Note>
  `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](/distribution/configure-nexus#gradle-android-desktop-jvm). A missing `rustls` artifact surfaces at runtime as `ClassNotFoundException: org.rustls.platformverifier.CertificateVerifier`.
</Note>

## 2. Initialize

`MBKYC.create()` returns an `MBKYCResult` — call `.getOrThrow()` if you prefer exceptions. On Android you must pass a `Context`.

```kotlin theme={null}
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](/concepts/authentication) for the token signer.

## 3. Discover readers & register

```kotlin theme={null}
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.

```kotlin theme={null}
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](/concepts/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](#hardware-support-model) below; no desktop service is needed.

<Tabs>
  <Tab title="Emirates ID">
    **Manual entry** — no hardware required.

    ```kotlin theme={null}
    EmiratesIdManual(idNumber = "784-XXXX-XXXXXXX-X", documentNumber = "...", nationality = "ARE")
    ```

    **Card read** — needs a USB CCID smart card reader.

    ```kotlin theme={null}
    EmiratesIdCard(readerId = reader.id)
    ```

    **NFC** — reads the chip over the device's built-in NFC (Android only).

    ```kotlin theme={null}
    EmiratesIdNfc(tag = tag)
    ```

    **+ Fingerprint** — attach a `fingerprint` to any Emirates ID request above to add a biometric match (needs a fingerprint sensor).

    ```kotlin theme={null}
    EmiratesIdCard(readerId = reader.id, fingerprint = fingerprint)
    ```
  </Tab>

  <Tab title="Passport">
    **Manual entry** — no hardware required. No biometric variant.

    ```kotlin theme={null}
    PassportManual(passportNumber = "...", passportType = "P", nationality = "IND")
    ```
  </Tab>
</Tabs>

Full initializers (optional params: `dateOfBirth`, `issueDate`, `expiryDate`, `fingerprint`, `clientReferenceId`) are in the [Full API reference](#full-api-reference).

## Fingerprint recommendation handler

The SDK calls this mid-flow with the Validation Gateway's quality-ranked finger list:

```kotlin theme={null}
val handler = FingerRecommendationHandler { recommended ->
    if (recommended.isNotEmpty()) FingerSelection.Recommended(recommended.first())
    else FingerSelection.Custom(Finger.RightIndex)
}
```

See [Biometrics](/concepts/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 reader | `class="11"`                         |
| IDEMIA (Morpho) MSO 1350   | `vendor-id="8797"` (0x225D)          |
| Suprema BioMini            | `vendor-id="5841"` (0x16D1)          |
| NEXUS / Zhiang             | `vendor-id="8309"` (0x2075)          |
| NFC                        | *not USB — handled via `NfcAdapter`* |

## Lifecycle

`MBKYC` is `AutoCloseable` — always close it:

```kotlin theme={null}
mbkyc.use { s ->
    s.validate(/* ... */)
}
```

<Warning>
  Build the `Fingerprint` via its constructor `Fingerprint(readerId, recommendationHandler, captureTimeoutMs)`. On Android, `MBKYC.create(context = ...)` requires a non-null `Context`.
</Warning>

## Full API reference

Every method returns `MBKYCResult<T>` (`Ok`/`Err`); call `.getOrThrow()` for exception semantics. Shared types ([`ReaderInfo`](/reference/data-types#readerinfo), [`RegistrationStatus`](/reference/data-types#registrationstatus), [`VerificationResult`](/reference/data-types#verificationresult), [`Finger`](/reference/data-types#finger), [`FingerSelection`](/reference/data-types#fingerselection)) are in [Data types](/reference/data-types).

| Method                                                                                                            | Returns                           |
| ----------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| `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`):

```kotlin theme={null}
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:

```kotlin theme={null}
mbkyc.exportLogs(File(filesDir, "mbkyc-logs.tar.zst")).getOrThrow()
```

Cancel a validation by cancelling the enclosing coroutine; the result resolves to a `CANCELLED` error.
