Mobile SDK Overview
The CICReader SDK reads the contactless chip inside a Vietnamese NID and returns both the raw data groups and the parsed citizen identity. It ships for Android, iOS and Flutter, plus a JavaScript bridge for WebView-based apps.
Platforms
| What | Description |
|---|---|
| Android | Kotlin. minSdk 21, Kotlin 1.7.10. Current version 1.0.6. |
| iOS | Swift. Xcode 16.0+, iOS 13+. Current version 1.0.7. |
| Flutter | Dart. Xcode 15.2+, Kotlin 1.7.10, iOS 13+, minSdk 21. Current version 1.0.8. |
| JavaScript bridge | For web pages running inside an Android or iOS WebView. Current version 1.0.8. |
What the SDK Does For You
One call performs the whole chip read and, optionally, the server-side verification.
| What | Description |
|---|---|
| Read the chip | Establishes the secure channel, then reads com, sod, dg1, dg2, dg13, dg14, dg15. |
| Verify against RAR | When enableCheckNfcData is true, sends the data groups to the Cake RAR server, which checks them and returns the parsed citizen fields plus a verificationKey. |
INFO
With enableCheckNfcData set to false the SDK returns only the raw data groups and cloneStatus — no citizen fields, no verificationKey. Every property marked API derived in the result tables depends on this flag being true.
Two Ways to Unlock the Chip
The chip will not open without a key derived from data printed on the card. The SDK supports both schemes.
| What | Description |
|---|---|
| MRZ — 9-digit ID + date of birth + expiry date | The ICAO scheme. Needs three inputs from the user. Throws IllegalMRZException / InvalidFullMRZKey when any is wrong. |
| CAN — 12-digit ID number | Card Access Number. Needs only the NID number, so it is the simpler flow. Added in version 1.0.3. Throws IllegalCanException / InvalidCANKey when wrong. |
Prefer CAN where your flow already has the full 12-digit number — it removes two input fields and two chances for the user to mistype.
WARNING
isVerified, cloneStatus and the other SDK results drive the UI only. Base the onboarding decision on Verify NFC called from your backend, after checking its X-Signature — never on values reported by the app.
Common Configuration
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
baseUrl | string | Yes | — | Base URL for API calls. |
enableCheckNfcData | bool | No | true | Verify NFC data by calling Cake RAR to confirm the data is valid and authorized. |
readTimeout | int | No | 60000 | API read timeout in milliseconds. |
writeTimeout | int | No | 60000 | API write timeout in milliseconds. |
cacheScanStrategy | enum | No | NO_CACHE | Cache a successful scan so a failed server call can be retried without re-scanning. See below. |
Every platform also accepts a header provider so you can attach custom headers to all SDK requests.
Runtime Inputs
Both read methods take these beyond the chip key:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
accessToken | string | Yes | — | The request access token, obtained by your backend from Create Transaction. |
refId | string | Yes | — | The transaction reference ID to be verified. |
Clone Status
Every result carries a cloneStatus describing what the verification concluded.
| Field | Type | Description |
|---|---|---|
notChecked | 0 | The card has not been checked yet. |
good | 1 | The card passed verification. |
alert | 2 | The card triggered an alert. |
error | 8 | An error occurred during the scan. |
Cache on Server Errors
When the chip read succeeds but the server cannot process the request, the SDK can cache the scanned chip data and retry the RAR call later without asking the user to tap the card again.
// Android
val config = CICConfig(
"<BASE_URL>",
true,
cacheScanStrategy = CICCacheScanStrategy.CACHE_FOR_VERIFY
)// iOS
CESNfcConfig(baseUrl: "<BASE_URL>",
cacheScanStrategy: .CACHE_FOR_VERIFY) // .NO_CACHE is the default// Flutter
final config = CakeNfcConfig(
baseUrl: "<BASE_URL>",
cacheScanStrategy: NfcCacheScanStrategy.CACHE_FOR_VERIFY,
);Android and Flutter key the cache by citizen id; iOS keys it by MRZ key.
WARNING
On a cache hit the SDK does not start a new chip scan, so nfcScanWillStart and nfcScanDidEnd never fire. On iOS this means you must render your own "verifying" UI from dataVerificationWillStart — otherwise the user sees a frozen screen while the RAR call runs.
Device Capability Helpers
| Field | Type | Description |
|---|---|---|
isNfcAvailable | bool | Whether NFC reading is available on the device. |
isNfcEnable | bool | Whether NFC is switched on. Android and Flutter only — always returns true on iOS. |
openNfcSetting | void | Opens the device NFC settings screen. Android and Flutter only. |
Next Steps
- Android SDK Integration — Kotlin integration guide
- iOS SDK Integration — Swift integration guide
- Flutter SDK Integration — Dart integration guide
- JavaScript Bridge — reading the chip from a WebView page
- Android SDK UI Customization — restyling the Android scanner screen