SDK for Android
Introduction
The IDEMIA Verify SDK for Android provides customers with the resources to customize the SDK to their preferred user-experience and integrate it within an existing mobile application. The IDEMIA Mobile ID Verify App works in conjunction with the IDEMIA Mobile ID App allowing verifiers to authenticate the user's physical ID or digital credential (i.e. drivers license or identity card).
You can use the SDK to:
-
Create and design your preferred user-experience and UI while leveraging the IDEMIA Verify functionalities
You can build a custom mobile application that implements your user-experience design and leverages all of the SDK functionalities allowing you to apply your branding and preferred user flow. You maintain complete control over the display and functionality of the application.
-
Embed IDEMIA Verify into an existing application
You can automatically integrate an existing mobile application with IDEMIA by adding the SDK frameworks, which removes the need to use and maintain an additional application to leverage the Mobile ID's functionalities.
Get Started
Skills Required
The integration tasks should be done by developers with knowledge of:
- Android Studio
- Java/Kotlin for Android
- Android SDK
- Android operating system
Resources Required
Integrations may be performed on PC Windows, Linux, or Macintosh.
- Android Studio Koala | 2024.1.1 or above
- Android SDK tools: preferred latest version (release 34 or above)
- JDK: preferred latest version (8 or above)
- Android device (emulator is not supported)
- Minimum SDK version is 30 (Android 11)
Other Requirements
Tech Stack | Description |
---|---|
Development environment | Android Studio Flamingo 2022.2.1+, Windows, Mac or Linux, JDK 8.. JDK17 |
Programming language | Kotlin, Java |
Kotlin Version | 1.8.20 |
Minimum supported OS Version | Android 11.0 (API 30) |
Target SDK version | Android 14.0 (API 34) |
Components
The SDK is made up of the following components:
IDVerify
acts as the entry point for initializing device engagement. It sends the request to the Mobile ID credential holder, receives the response, and sends the parsed model back to the calling app. It exposes the following APIs to the caller/client:
SDK Core APIs
- version
Kotlin1/**2* returns build version if IDVerify sdk in <versionName>-<VersionCode> format.e.g. 4.2.0-1343* Integrators can use this information to know and validate IDVerify version they are to integrate in their app.4* /56//Usage7Log.d(TAG, "SDK Version=${IDVerify.version}")
- initializeSDK
Kotlin1/**2 * Call this static function to activate the license very first time before initialising IDVerify.3 * @param lkmsConfig : Model class containing with license configurations details e.g. APIKey, ActivationId etc.4 * @param context: application context5 * @param callback : return success or error6 * returns error or success callback7 * Note: It is mandatory to call initializeSDK function at least once when reader app loads -- with valid license configurations.8 * Using any other IDVerify APIs without calling this function might result in error.9 */10fun initializeSDK(lkmsConfig: LkmsConfig?, context: Context?, callback: SuccessCallback<Boolean>)
- getClient
Kotlin1/**2 * Create and return IDVerify client object.3 *4 * @param configs – required configurations to initialize IDVerify instance5 * @param actContext; activity context from app.. you can provide an application or6 * Activity context however some features e.g. NFC, WifiAware it is strictly required7 * Activity context; hence it is recommended to use Activity context. It is also recommended8 * that your app maintain a singleton object of SDK to avoid any concurrency issues.9 *10 * @return `IDVerify` interface to access the ISO reader APIs11 */1213fun getClient(configs: VSDKConfigs, actContext:Context): IDVerify
- loadCertificates
Kotlin1/**2 * Load certificates from a given location from device storage path3 * @param path from device storage if accessible directly; defaults to null if not supplied4 * @param vical file path from device storage if accessible directly.5 * defaults to null if not supplied and fallback to load vical from assets/vical folder if available6 * @param callback async callback to return success or error7 */89fun loadCertificates(path: String?=null,callback: SuccessCallback<Int>?)
- initDeviceEngagement
Kotlin1/**2 * perform device engagement using QR code / NFC3 * @param apiConfigs apiConfigs to configure QR code/NFC flow etc.4 * Uses:5val apiConfigs = ApiConfigs.Builder()6.withData(scannedData) // for qr code device engagement7//OR .withConfigs().useNfcHandover().buildConfigs() //for nfc device engagement8.build()910 * @param deviceEngagementCallback callback to return the DeviceEngagement model11 * and/or other events during engagement.12 * Usage:13<p>14sdkClintV2.initDeviceEngagement(apiConfigs,object:DeviceEngagementCallback(){15//override the interface methods here16})17</p>18 */19fun initDeviceEngagement(apiConfigs: ApiConfigs?, callback: DeviceEngagementCallback<in ResponseItem?>)
- prepareConnection
Kotlin1/**2 * Initialize and setup connection components as per`ConnectionConfigs` configurations supplied.3 * This API is available in `IDVerify` only and must be called explicitly if SDK client4 * is created using `IDVerify.getClient`.5 */67fun prepareConnection(apiConfigs: ConnectionConfigs, callback: PrepareConnectionCallback?)
- sendRequest
Kotlin1/**2 * send request to Mobile ID based on the use case selected by user in Verify application3 * @param apiConfigs: configurations and optional Mobile ID request params4 * @param callback: callback to send progress and response data back to app5 *6 * 1. create Mobile ID request based on supplied Use Case or parameters/configs7 * 2. onCreate communication channel (BLE/NFC/wifiAware ...) as per engagement data8 * 3. send request to Mobile ID on communication channel9 */10fun sendRequest(apiConfigs: ApiConfigs? = ApiConfigs.Builder().build(),11 callback: ICallback<in ResponseItem?, in ProgressItem>)
- cancelRequest
Kotlin1/**2 * cancel any transaction/running session with Mobile ID. overload to default cancellation3 * return true if transaction is cancelled successfully4 */5fun cancelRequest(): Boolean
- terminateConnection
Kotlin1/**2 * Terminate the current connection to let user call prepareConnection again.3 */4fun terminateConnection(): Boolean
- terminateSession
Kotlin1/**2 * Terminate/Close the connection, wipe out session data and ready to process next transaction from3 * user.4 */5fun terminateSession(): Boolean
- isRequestOngoing
Kotlin1/**2 * Check whether a transaction is already setup and in-progress state. Integrator can use this3 * api to check a running transaction and cancel (if needed using `cancelRequest`) before4 * starting a fresh transaction.5 * Normally this api may not be used because once the transaction is complete verify SDK will return6 * to initial state, however in case of some negative test cases it may be useful to check before7 * starting a new transaction.8 */9fun isRequestOngoing(): Boolean
User Permissions
When designing your app, you need to consider that your Android app must handle end-user permissions to protect the resources on the target mobile device. You have to verify that the end-user grant the following permissions to the app:
- Camera permission (for QR code scanning using Camera)
- Location permission (when BLE client mode and WiFiAware use cases)
- Nearby devices permission required for WiFiAware use case (android 13 and above)
The end-user must grant access when using an Android version higher than 2.3 (Android 6.0 Marshmallow). The SDK will throw an exception or error, if the required permissions are not granted.
Sample Project
Download the IDEMIA Verify Sample App – Android using below URL: https://mi-artifactory.otlabs.fr/artifactory/verify-sdkpro-release/com/idemia/android/idverify/4.2.0/Sample/
Create Your Own App
Follow the steps mentioned below to Integrate the VerifySDK in your App:
Step 1: Add the Verify Library dependencies in your Android project
To create your own app, you must add the VerifySDK libraries to your project. There are two ways of doing this:
** Import VerifySDK from mi-artifactory**
- Add the following configs in gradle.properties as shown in the snippet:
Groovy1artifactory_remoteUrl=https://mi-artifactory.otlabs.fr/artifactory/verify-sdkpro-release2artifactory_username=<username>3artifactory_password=<password>
- Add the following dependency in your project/build.gradle as shown in the snippet:
Groovy1buildscript {23 repositories {4 google()5 jcenter()6 maven {7 url "https://plugins.gradle.org/m2/"8 }9 //required below maven block to sync verify SDK artifact from mi-artifactory10 maven {11 url "${artifactory_remoteUrl}"12 credentials {13 username = "${artifactory_username}"14 password = "${artifactory_password}"15 }16 }1718 }19 ...20 }21 ...2223 allprojects {24 repositories {25 ...26 maven { url 'https://github.com/c-rack/cbor-java' }27 maven {28 url "${artifactory_remoteUrl}"29 credentials {30 username = "${artifactory_username}"31 password = "${artifactory_password}"32 }33 }3435 }36 project.ext{37 sdkVersionName='4.2.0'38 sdkVersionCode=134 //use latest release version number for v4.2.0 from mi-artifactory3940 }4142 }
- Add following dependency in app/build.gradle as shown in the snippet:
Groovy1dependencies {2 implementation("com.idemia.android:idverify:${project.ext.sdkVersionName}-${project.ext.sdkVersionCode}@aar") {3 transitive = true4 }5 ...6}
Additional Steps to Compile and Build your Android project
- Add the required permissions to the project:
XML1<!-- required camera for QR code scanning-->2 <uses-permission android:name="android.permission.CAMERA"/>3 <uses-feature android:name="android.hardware.camera.any" />4 <!-- Request legacy Bluetooth permissions on older devices. -->5 <!-- required for BLE data transfer-->6 <uses-permission android:name="android.permission.BLUETOOTH"7 android:maxSdkVersion="30"/>8 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"9 android:maxSdkVersion="30"/>10 <!--BLE permissions for Android 12-->11 <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />1213 <!-- Needed only if your app makes the device discoverable to Bluetooth14 devices. -->15 <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />1617 <!-- Needed only if your app communicates with already-paired Bluetooth18 devices. -->19 <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />2021 <!-- required for wifiaware and BLE scanning -->22 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />23 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />24 <!--Required for online use cases -->25 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />26 <uses-permission android:name="android.permission.INTERNET" />27 <!-- required for wifiaware data transfer-->28 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />29 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>30 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>31 <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation"/>32 <!-- required for nfc data transfer-->33 <uses-permission android:name="android.permission.NFC"/>
- In order to allow your app to install in devices which do not support a certain feature, below lines can be added just below the permissions:
XML1<!-- Do not install in devices which do not have Camera -->2 <uses-feature android:name="android.hardware.camera" android:required="true"/>3 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>4 <!-- allow app to install in devices which do not have NFC support so that5 they can still use other features e.g QR code and WifiAware use-cases -->6 <uses-feature android:name="android.hardware.nfc" android:required="false"/>7 <!-- allow app to install in devices which do not have wifiAware support so that8 they can still use other features e.g QR code and NFC use-cases -->9 <uses-feature android:name="android.hardware.wifi.aware" android:required="false"/>
Note: It is not recommended to have all three configs with
required="false"
. Normally if all three use cases (QR Code, NFC handover/transfer, WifiAware Transfer) are supported in your app then you may want to let users install your app regardless of their device supports or not NFC and/or WifiAware; for that you can addrequired="false"
for WifiAware and NFC andrequired="true"
for Camera.
- Gradle Sync and build!
Step 2: Integrate QR Code + BLE/NFC/WiFi Use case
- Initialize the ID Verify SDK by providing a valid license information in
initializeSDK
API. Best way to do it is when your application's Home Activity is loaded inside theonCreate
function:
Kotlin1override fun onCreate(savedInstanceState: Bundle?) {2 super.onCreate(savedInstanceState)3 initIdVerify(getLicenseConfigs())45 //.. other code here6 // setupQRCodeScanner(scanMode)7 }89 private fun initIdVerify(lkmsConfig: LkmsConfig) {10 IDVerify.initialiseSDK(lkmsConfig,this,object: SuccessCallback<Boolean> {11 override fun onSuccess(status: Boolean?) {12 //show/log any message or keep silent13 }14 override fun onError(error: IError?) {15 //display error as returned by ID Verify SDK. and prompt the user to exit the app since ID Verify SDK can not function until this error is fixed.16 }17 })18 }1920 /**21 * License configs can be managed as BuildConfig fields and loaded at runtime.22 */23 protected open fun getLkmsConfigs(): LkmsConfig {24 return LkmsConfig(25 BuildConfig.lkmsURL,26 BuildConfig.lkmsProfileId,27 BuildConfig.lkmsApiKey,false)28 }
- Once the ID Verify SDK is initialized with a valid license, you may create the IDVerify object to access all the Verifier APIs. Below code snippet shows how to create IDVerify interface
mIdVerify
:
Kotlin1val config = VSDKConfigs.Builder().build()2 mIdVerify = IDVerify.getClient(config,actContext)
Important:
- While building VSDKConfigs you may use
enableDebug
function to get the live logs viaDebugCallback
and save them in a file, as shown in the snippet:
Kotlin1val config = VSDKConfigs.Builder(this)2 .enableDebug(LogLevel.DEBUG,debugCallback = object:DebugCallback{3 override fun didReceiveLogs(logs: DLog) {4 //save or print logs here5 //6 }7 })8 ...9 .build()
Note: It is recommended to save the logs into a file and then print or share the file to see the full logs. Because logcat strips logs if they are too big to fit in console.. for example, response bytes with end-user image becomes too big to print in logcat.
- Enabling debug verbose logs in the production app may adversely affect the transaction speed and overall performance of the Verify SDK for Android.
- It is recommended that integrator should use the LogLevel properties carefully to configure limited logs in production flavour.
- Default LogLevel will be NONE if
enableDebug
is not configured with at least one LogLevel - If you want full debug logs except PIIs then use DEBUG_NO_PII
- DEBUG and VERBOSE may include PIIs hence should be avoided in production release
- Supported LogLevel are:
Language not specified1TRANSACTION_TIME : Only transaction time event logs shall be printed on console and returned to`debugCallback.didReceiveLogs()`2 These logs shall be persisted in runtime memory during the transaction and shall be dumped3 to console in a time sorted order (FIFO) once the transaction concludes.45 TROUBLESHOOTING : Only minimal troubleshooting logs (e.g. exceptions and errors) shall be printed on console and6 returned to `debugCallback.didReceiveLogs()`.7 These logs would be helpful to troubleshoot the failures cases during transactions.89 DEBUG : All debug logs include PIIs are returned or printed in console1011 DEBUG_NO_PII : All except PII logs shall be returned to `debugCallback.didReceiveLogs()` LogLevel.DEBUG_NO_PII has highest priority12 if multiple logLevel values are configured via `enableDebug` vararg param. (excluding LogLevel.NONE- in case of NONE is found,13 all other configs shall be ignored and all logs shall be disabled)1415 VERBOSE : Allow all logs (transaction_time, troubleshooting, and Debug) including PIIs1617 NONE : No logs shall be printed. LogLevel.NONE has highest priority if multiple18 logLevel values are configured via `enableDebug` vararg param
2.1. Call loadCertificates()
api to load IACA certificates from given path. This step is necessary for a successful transaction since
Verify SDK will validate the mDL response against the certificates from supplied path.
Kotlin1mIdVerify?.loadCertificates(path=<directory_path/vical>,object : SuccessCallback<Int> {2 override fun onSuccess(response: Int?) {3 Log.d("HomeFragment","*Certificate Loading, loaded cert count:$response")45 }6 override fun onError(error: IError?) {7 Log.d("HomeFragment","*Certificate Loading error: ${error?.errorCode}")8 }9 })
How to create directory structure for hosting vical files for your Reader app?
- Copy download vical files at some app private location which should be accecisble at runtime
- Create new directory vical/ inside assets and copy iaca files for each environment as per below structure.
- assets/vical
- Dev
- iaca.vical
- iaca.vical.pem
- UAT
- iaca.vical
- iaca.vical.pem
- PROD
- iaca.vical
- iaca.vical.pem
- Dev
Note:
- The vical file and corresponding IACA file to validate vical coseSign1 should be named exactly as in above sample
- For example, if vical file name is "myiaca.vical" then IACA should be named "myiaca.vical.pem"
How To configure vical from app/assets directory?
- Create 'assets/vical' folder inside app/main or app/flavorName/
- Copy iaca and corresponding IACA cert per environment similar to structure defined above.
- Set value for
path
tonull
while callingloadCertificates
api and verifySDK shall fallback to use assets/vical path
Kotlin1.loadCertificates(path=null,callback=object :SuccessCallback<Int>{2 override fun onSuccess(response: Int?) {3 //Log.d("HomeFragment","*Certificate Loading, loaded cert count:$response")4 }56 override fun onError(error: IError?) {7 //Log.d("HomeFragment","*Certificate Loading error: ${error?.errorCode}")8 }910 })
Note:
loadCertificates()
api should be called only once on application launch when SDK object is created first; no need to be called for each transaction.
- Call the desired SDK API by supplying the necessary
apiConfigs/request
parameters and using callback to receive the results.
Kotlin1* `mIdVerify.initDeviceEngagement(apiConfigs,callback)`2* `mIdVerify.prepareConnection(connectionConfigs,callback)`3* `mIdVerify.sendRequest(apiConfigs,callback)`4* `mIdVerify.terminateConnection()`5* `mIdVerify.terminateSession()`6*
- To scan the QR code follow the below steps to communicate with the Mobile ID App and display the results on the Verify App screen:
- Scan the QR code using Zxing or any other library and then call
initDeviceEngagement
API as shown in the snippet:
Kotlin1fun onQRCodeScanned(scannedData: String?) {2 doHandleScannedData(scannedData)3 }
- Create the response callback for parsing engagement QR code data as shown in the snippet:
Kotlin1open fun doHandleScannedData(scannedData: String?) {2 if (!scannedData.isNullOrEmpty()) {3 val nfcConfigsBuilder=NfcConfigs.Builder()4 val apiConfigs = ApiConfigs.Builder()5 .withData(scannedData)6// //OR useNfcHandover() as below commented section//for nfc device engagement7// .withConfigs().apply {8// useNfcHandover()9// /* use additional configs for nfcHandover if needed10// * verify sdk will use default and best ppossible configs if no configs are11// * set using `setNfcConfigs`12// */13//14// nfcConfigsBuilder.enableReaderEngagement() //use this cofig to enable readerEngagement bytes ON for Nfc negotiated handover15// nfcConfigsBuilder.enableWiFiACRecord(true) //use this to indicate support for WiFiAware16// nfcConfigsBuilder.leRole(LeRole.MDOC_CENTRAL_ONLY) // use this to indicate preferred LE Role17// //... // additional configs to fine tune based on underlying hardware/device/OS if needed18// setNfcConfigs(nfcConfigsBuilder.build())19// }20// .buildConfigs()21 .build()22 mIdVerify?.initDeviceEngagement(apiConfigs, mDEParserCallback)23 } else {24 // QR scan failed! try again25 }26 }27 /** Response callback for parse engagement QR code data */28 private val mDEParserCallback = object : ResponseCallback<DeviceEngagementModel?> {29 override fun onSuccess(deviceEngegmentModel: DeviceEngagementModel?) {30 // deviceEngegmentModel received. perform next step31 doPrepareConnection(deviceEngagementModel)32 // OR for legacy client33 // doStartDataTransfer(deviceEngagementModel)34 }35 override fun onError(error: IError?) {36 handleError(error)37 }38 }
- Call
prepareConnection
api before calling sendRequest else skip to step 5.1
Kotlin1private fun doPrepareConnection(deModel: DeviceEngagementModel?) {2 val connectionConfigs = ConnectionConfigs.Builder()3 .withConfigs().apply {4 setResponseTimeout(10000) //sdk will disconnect and return with error code 303 if transaction doesn't complete in this time5 setConnectTimeout(10000) //sdk will return with error code 206 is connection not established withing this time6 //enableL2Cap() //to enable BLE l2cap if available and supported78 }.buildConf()9 .build()10 mIdVerify?.prepareConnection(connectionConfigs,11 object : PrepareConnectionCallback {12 override fun onSuccess(response: ConnectionInfo?) {13 when (response?.connectionState) {14 ConnectionState.CONNECTED -> {15 doStartDataTransfer(deModel)16 }17 else -> {18 Log.d("MainActivity","prepareConnection: connectionState=${response?.connectionState}")19 }20 }21 }2223 override fun onError(error: IError?) {24 handleError(error)25 }26 })27 }
5.1. Send the request to the Mobile ID App to get the credential details. The sendRequest()
method will return the response from the user's Mobile ID App. If you've received it successfully, then you can display all the attributes of the Mobile ID App response in your own result activity, as shown in the snippet:
Kotlin1private fun doStartDataTransfer(deModel: DeviceEngagementModel?) {23 val namespaceParamMap = getRequestedParamsMap() // make map of namespace to List<MIDRequestParam>45 val apiConfigs = ApiConfigs.MIDRequestBuilder()6 .version("1.0")7 .withConfigs().apply {8 //verify sdk will disconnect and return with error code 303 if transaction doesn't complete in this time9 setResponseTimeout(20000)10 //verify sdk will return with error code 206 is connection not established withing this time11 setConnectTimeout(10000)12 clearBLECache() // enable BLE cache to clear for every transaction to avoid connection issues13 //for wifiaware data transfer; since v2.4.014 setNANConfigs(NANConfigs.Builder().apply {15 setSubscribeType(DEFAULT_NAN_SUBSCRIBE_TYPE)16 setTtlSec(15)17 }.build())18 }.buildConf()19 //add docType20 .addDocType(DOCTYPE_18013_5).apply {21 // pass all request params as Map<namespace->List<MIDRequestParam>22 addParams(namespaceParamMap)23 //OR use namespace -> param overload to add all params one by one24 addParam("org.aamva.us", MIDRequestParam(REAL_ID))25 addParam("org.aamva.us", MIDRequestParam("<AttributeName>"))26 //OR use another overload to . duplicate params shall be removed if found27 addParams(DEFAULT_NAMESPACE_18013_5_1, namespaceParamMap.get(DEFAULT_NAMESPACE_18013_5_1))28 addParams(NAMESPACE_ORG_ISO_AAMVA, namespaceParamList.get(NAMESPACE_ORG_ISO_AAMVA))29 //OR this way30 addParams(31 "my.custom.namespace2", listOf(32 MIDRequestParam("custom_param_nm21"),33 MIDRequestParam("custom_param_nm22"),34 MIDRequestParam("custom_param_nm23"),35 MIDRequestParam("custom_param_nm21") //duplicate36 )37 )38 //OR use 3rd overload to pass params one by one39 .addParam("my.custom.namespace", MIDRequestParam("custom_param1"))40 // add requestInfo as map41 .addRequestInfo(42 infoMap = hashMapOf(43 "reqKey1" to "reqVal1",44 "reqKey2" to "reqVal2",45 "reqKey3" to false,46 "reqKey4" to 333447 )48 )49 //or use other overload to add one by one50 .addRequestInfo("reqinfo1", "value1")51 .addRequestInfo("reqinfo2", "value2")52 .addRequestInfo("reqinfoLong", 180L)53 .addRequestInfo("reqinfoBool", true)54 .addRequestInfo("reqinfoBytArr", "sdkghdkgs".toByteArray())55 .addRequestInfo("reqinfoDouble", 3.7)56 .addRequestInfo("reqinfoFloat", 3.7F)57 // add as dataItem58 .addRequestInfo(59 "reqinfoDataItem",60 CborBuilder().addArray().add(1).add("item2").add("item3").end().build()61 .first()62 )6364 }.buildDoc()65 //add another docType66 .addDocType("my.cusom.docType.custom").apply {67 addParams(68 "my.custom.namespace2", listOf(69 MIDRequestParam("custom_param_nm21", true),70 MIDRequestParam("custom_param_nm22"),71 MIDRequestParam("custom_param_nm23"),72 MIDRequestParam("custom_param_nm21", true) //duplicate73 )74 )75 // add requestInfo as map76 .addRequestInfo(77 infoMap = hashMapOf(78 "reqKey1" to "reqVal1",79 "reqKey2" to "reqVal2",80 "reqKey3" to false,81 "reqKey4" to 333482 )83 )84 }.buildDoc()85 //(optional) setReaderAuthentication callback if needed86 .setReaderAuthCallback(readerAuthSigner,ReaderAuthAlgorithm.ALGO_SHA256WITHECDSA)87 //(optional) Use setMultiRequestCallback to enable multiple requests-response exchanges within same session.88 .setMultiRequestCallback(multiResCallback)89 .build()9091 if (deModel?.isMDLAsPeripheral()) {92 askLocationPermission() /* android.permission.ACCESS_COARSE_LOCATION to be added in AndroidManifest.93 you may invoke all permission dialogs beforehand to avoid this check here*/94 //mIdVerify?.sendRequest(apiConfigs, callback = mRequestCallback) //get permission and then call sendRequest95 } else {96 mIdVerify?.sendRequest(apiConfigs, callback = mRequestCallback)97 }9899 }100101 fun getRequestedParamsMap(): java.util.HashMap<String, List<MIDRequestParam>> {102 val paramMap= hashMapOf<String, List<MIDRequestParam>>()103 paramMap.put(NAMESPACE_18013_5,listOf(104 MIDRequestParam(FAMILY_NAME),105 MIDRequestParam(GIVEN_NAME),106 MIDRequestParam(BIRTHDATE),107 MIDRequestParam(ISSUE_DATE),108 MIDRequestParam(EXPIRY_DATE),109 MIDRequestParam(ISSUING_COUNTRY),110 MIDRequestParam(ISSUING_AUTHORITY),111 MIDRequestParam(DOCUMENT_NUMBER),112 MIDRequestParam(PORTRAIT),113 MIDRequestParam(MGMT_LAST_UPDATE)))114115 paramMap.put(NAMESPACE_ORG_ISO_AAMVA,listOf(MIDRequestParam(DHS_COMPLIANCE),116 MIDRequestParam(DOMESTIC_DRIVING_PRIVILEGES)))117118 return paramMap119 }
**Sample code for Reader Authentication callback implementation **
Reader Authentication is an optional setReaderAuthCallback
which can be used by the integrator to implement Reader Auth for their Verifier app.
Below sample code spec illustrates how Reader Authentication callback can be implemented:
a. Add/Enable the callback in the RequestBuilder
Kotlin1val apiConfigs = ApiConfigs.MIDRequestBuilder()2 .version("1.0")3 .addDocType("my.cusom.docType.custom").apply {4 addParams( … )5 }.buildDoc()6 …7 .setReaderAuthCallback(readerAuthSignerCallback,readerAuthAlgorithm)8 .build()
b. Implement the readerAuthSignerCallback at app side. ReaderAuthSignerCallback provides the interface to perform signing of readerAuthentication structure. Verify SDK will call doSignRequest with the readerAuthentication structure to sign by the integrator with the reader private key. They will sign the bytes using certificate private key and return ReaderAuthSign data model with generated signature, algorithm used to sign and a x509 certificate with the corresponding public key of the private key that the readerAuthenticationBytes structure is signed. [Refer 9.1.4 mdoc reader authentication ISO/IEC FDIS 18013-5:2021(E) page 54]
Kotlin1val readerAuthAlgorithm = ReaderAuthAlgorithm.ALGO_SHA256WITHECDSA2 val readerAuthSigner=object : ReaderAuthSignerCallback {3 override fun doSignItemRequest(readerAuthenticationStructure: ByteArray?,docType:String): ReaderAuthSign? {4 // Verify SDK provides some utility functions in VIDUtils which can be used or write your own logic to generate the signature5 val signatureBytes = VIDUtils.generateReaderAuthSignature(readerAuthAlgorithm, readerAuthPrivateKey, readerAuthenticationStructure)6 val certItem=CborBuilder().add(x509Certificate).build().firstOrNull()7 return ReaderAuthSign(signature = signatureBytes,x509Certificate = certItem)8 }
c. List of required resources e.g cert, keys. at Integrator side.
- Reader private key to sign the Reader Auth structure. the resulting signature and algorithm used to sign shall be included within the mdoc request to be sent to mdoc.
- Reade Signer certificate containing the corresponding public key of the private key used in #a; which shall be sent to mdoc within the mdoc request. Integrator would submit a CSR to a valid CA to get a signer certificate.
- Reader CA certificate from CA which shall be shared by Reader to mDoc Holder which they can uses for signer certificate trust path validation
** Sample code for multiReqCallback **
Kotlin1val multiResCallback = object : MultiResponseCallback<ResponseItem?> {2 override fun onMultiResponse(3 response: ResponseItem?,4 requestCallback: MultiRequestCallback5 ): Boolean {6 /*7 * 1. process the `response` and analyse or display if needed8 * 2. check if new request is required to send: y/n9 * - if y. create a new request using ApiConfigs.MIDRequestBuilder() and send back using10 * `requestCallback.onNextRequest()`11 * - if n, return false and wait for onSuccess or onError with final response12 */13 handleMultiResponse(response,requestCallback)14 return true15 }1617 }
Sample code for setCrlDownloaderCallback
[optional].
Kotlin1/**2* Use this setter `setCrlDownloaderCallback` to configure the callback for CRL downloading via application side and return to verifySDK.3 *4* @param crlDownloaderCallback callback to be used by verifySDK to pass CRL distribution point URL(s) and return the downloaded crl data back to verifySDK.5 * Default it is set to null if not set by app / integrator - which means verifySDK shall only check the CRL loaded from Vical only (if present).6* @param forceDownload when true- verifySDK to ignore already available crl from vical (if present) and use crlDownloaderCallback to get it downloaded via ap; dafault is false.7* @param timeoutInMillis - verifySDK waits for app to download and return the crl data, default timeout is DEFAULT_CLR_DOWNLOAD_TIMEOUT=3 seconds8* till this timeout else skips crl check and assumes certificate as NOT Revoked.9*/1011fun setCrlDownloaderCallback(crlDownloaderCallback: CRLDownloaderCallback?=null,12 forceDownload:Boolean=false,13 timeoutInMillis:Long=DEFAULT_CLR_DOWNLOAD_TIMEOUT)
- Here are the steps to follow by application integrator to use above callback:
Step1. Declare and implement the callback object
Kotlin1protected val crlCheckCallback=object: CRLDownloaderCallback {2 override fun doDownload(crlDpUrlList: List<String>): CrlDownloaded? {3 val completableFuture = CompletableFuture<CrlDownloaded>()4 // check if same CRL is already download within last 24 hours or as per the timeout managed5 //if timeout is reached or exceeded; clean the cache and return null or empty in `crlFromCache`6 val crlFromCache=loadFromCache(crlDpUrlList)7 if(crlFromCache?.isNotEmpty() == true){8 completableFuture.complete(CrlDownloaded(crlFromCache))9 return completableFuture.get()10 }11 if(!AppUtils.isInternetConnected(this@BlinkIDScanActivity)){12 logAny("$crlCheckTag Connectivity error:Could not download CRL from remote, return null")13 return null14 }15 //else download from remote and return16 lifecycleScope.launch {17 try {18 //Download the same the data and download time in cache19 val downloadedCrls = DownloadManager(this@BlinkIDScanActivity).downloadCrlDataList(crlDpUrlList)20 completableFuture.complete(CrlDownloaded(downloadedCrls))21 } catch (e: Exception) {22 logAny("$crlCheckTag CRL Downloaded failed due to an exception:${e.message}, return null")23 completableFuture.completeExceptionally(e)24 }25 }2627 return completableFuture.get()28 }2930 }
Step 2. Set the callback in request configuration model similar to setReaderAuthCallback
Kotlin1val timeoutConfig=5000L2 val isForceDownloadConfig=true // true indicates ignore the crl received from Vical and use the downloaded one3 val apiConfigs = ApiConfigs.MIDRequestBuilder()4 .version("1.0")5 .addDocType("<tocType>").apply {6 addParams(<paramsList>)7 }.buildDoc()8 .addDocType("<tocType2>").apply { // configure another docType9 addParams(<paramsList2>)10 }.buildDoc()11 …12 .setReaderAuthCallback(readerAuthSignerCallback,readerAuthAlgorithm)13 .setCrlDownloaderCallback(crlDownloaderCallback, forceDownload = isForceDownloadConfig,timeoutConfig)14 .build()
- Obtain the response callback for parsing the engagement QR code data scan as shown in the snippet:
Kotlin1/**2 * Request callback for sendRequest SDK api to receive and display response data from Mobile ID3 */4 val mRequestCallback = object : RequestCallback<ResponseItem?, ProgressItem> {56 override fun onSuccess(response: ResponseItem?) {7 Log.e(TAG, "Mobile ID response:$response")8 displayResponse(response as DLDataModel)9 }1011 override fun onError(error: IError?) {12 handleError(error = error as VSDKError)13 }1415 override fun onProgress(progress: ProgressItem) {16 Log.e(TAG, progress.toString())17 }1819 }
- You can cancel/terminate a transaction any time if an error occurs in the app, or if the user cancels the transaction by tapping the Back button. Cancel a transaction by calling the
terminateSession()
method as shown in the snippet:
Kotlin1mIdVerify?.terminateSession()
7.1. In order to close a running connection and start another connection using prepareConnection
use terminateConnection
API
Kotlin1mIdVerify?.terminateConnection()
Integrate NFC Handover + BLE/NFC/WiFi Use case
- Initialise NFC device Engagement
Kotlin1val apiConfigs = ApiConfigs.Builder()2 .withConfigs().apply {3 useNfcHandover()4 //setBLEMacAddress(bleMacAddress) for mac address connect use this option5 setNfcConfigs(NfcConfigs.Builder().setPresenceCheckDelay(1000)6 .addNfcDetectCallback(object:NfcConfigs.NfcDetectCallback{7 override fun onTagDiscovered(tag: Tag?): Boolean {8 // indicates new nfc tag is discovered. return true to process the tag9 // you may add / display some progress indicator for user10 // once the handover is done, feedback will be received in mDEParserCallback11 return true12 }13 })14 .build())15 //...16 }.buildConfigs()17 .build()18 mIdVerify?.initDeviceEngagement(apiConfigs, mDEParserCallback)
-
After device engagement is complete, follow the same steps as described above
-
To configure NFC or Wifi as data transfer method add configs in
ConnectionConfigs
Builder.
Kotlin1val connectionConfigs = ConnectionConfigs.Builder()2 .withConfigs().apply {3 setResponseTimeout(10000) //sdk will disconnect and return with error code 303 if transaction doesn't complete in 10 seconds4 setConnectTimeout(10000) //sdk will return with error code 206 is connection not established withing 10 seconds5 useNfc() // or useWifi() // or connectAsmDocPeripheral() or connectAsmDocCentral6 }.buildConf()7 .build()
Note:
- By default BLE mDoc Central mode is the preferred mode if multiple modes are available from mDL holder
- From Reader side verify SDK allows the integrator to configure the preferred connection mode, however if configured mode is not available, VerifySDK will try to connect using whichever mode is available with mDL holder
Request Parameters
The following table provides a list of attributes which can be configured for sendRequest
API.
Item# | Identifier | Param Name | CBOR Type |
---|---|---|---|
Namespace= "org.iso.18013.5.1" | |||
1 | ADMINISTRATIVE_NUMBER | administrative_number | Major type 3 |
2 | SEX | sex | Major type 3 |
3 | HEIGHT | height | Major type 0 |
4 | WEIGHT | weight | Major type 0 |
5 | EYE_COLOR | eye_color | Major type 3 |
6 | HAIR_COLOR | hair_color | Major type 3 |
7 | BIRTH_PLACE | birthplace | Major type 3 |
8 | RESIDENT_ADDRESS | resident_address | Major type 3 |
9 | PORTRAIT_CAPTURE_DATE | portrait_capture_date | Tag value 0 of major type 6 |
10 | AGE_IN_YEARS | age_in_years | Major type 0 |
11 | AGE_BIRTH_YEAR | age_birth_year | Major type 0 |
12 | AGE_OVER_NN | age_over_NN | Value 20/21 of major type 7 |
13 | ISSUING_JURISDICTION | issuing_jurisdiction | ajor Type 3 |
14 | NATIONALITY | nationality | Major type 3 |
15 | RESIDENT_CITY | resident_city | Major type 3 |
16 | RESIDENT_STATE | resident_state | Major type 3 |
17 | RESIDENT_POSTAL_CODE | resident_postal_code | Major type 3 |
18 | BIOMETRIC_TEMPLATE_XX | biometric_template_xx | Major type 2 |
19 | NAME_NAT_CHAR | name_nat_char | Major type 3 |
20 | MGMT_NEXT_UPDATE | mgmt_nextupdate | Tag value 0 of major type 6 |
21 | FAMILY_NAME | family_name | Major type 3 |
22 | GIVEN_NAME | given_name | Tag value 0 of major type 6 |
23 | BIRTHDATE | birthdate | Tag value 0 of major type 6 |
24 | ISSUE_DATE | issue_date | Tag value 0 of major type 6 |
25 | EXPIRY_DATE | expiry_date | Major type 3 |
26 | ISSUING_COUNTRY | issuing_country | Major type 3 |
27 | ISSUING_AUTHORITY | issuing_authority | Major type 3 |
28 | DOCUMENT_NUMBER | document_number | Major type 3 |
29 | PORTRAIT | portrait | Major type 2 |
30 | MGMT_LAST_UPDATE | mgmt_lastupdate | Tag value 0 of major type 6 |
31 | MGMT_VALIDITY | mgmt_validity | Tag value 0 of major type 6 |
32 | ONLINE_TOKEN_XXXX | online_token_xxxx | Major type 3 |
34 | DRIVING_PRIVILEGES | driving_privileges | Major type 4 |
35 | SIGNATURE_USUAL_MARK | signature_usual_mark | Major type 3 |
36 | ONLINE_URL_XXXX | online_url_xxxx | Major type 3 |
37 | BIRTHDATE | birth_date | Major type 3 |
38 | BIRTH_PLACE | birth_place | Major type 3 |
39 | NAME_NAT_CHAR | name_national_character | Major type 3 |
40 | FAMILY_NAME_NATIONAL_CHAR | family_name_national_character | Major type 3 //added in N19xx |
41 | GIVEN_NAME_NATIONAL_CHAR | given_name_national_character | Major type 3 //added in N19xx |
Namespace= "org.iso.18013.5.1.aamva" | //based on mDL-Implementation-Guidelines-1-0_2021.pdf | ||
1 | DOMESTIC_DRIVING_PRIVILEGES | domestic_driving_privileges | Major type 3 |
2 | DHS_COMPLIANCE | DHS_compliance | Major type 3 |
3 | NAME_SUFFIX | name_suffix | Major type 3 |
4 | ORGAN_DONOR | organ_donor | Major type 0 |
5 | VETERAN | veteran | Major type 0 |
6 | FAMILY_NAME_TRUNCATION | family_name_truncation | Major type 3 |
7 | GIVEN_NAME_TRUNCATION | given_name_truncation | Major type 3 |
8 | AKA_FAMILY_NAME_V2 | aka_family_name.v2 | Major type 3 |
9 | AKA_GIVEN_NAME_V2 | aka_given_name.v2 | Major type 3 |
10 | AKA_SUFFIX | aka_suffix | Major type 3 |
11 | WEIGHT_RANGE | weight_range | Major type 0 |
12 | RACE_ETHNICITY | race_ethnicity | Major type 3 |
13 | EDL_CREDENTIAL | EDL_credential | Major type 0 |
14 | SEX | sex | Major type 0 |
15 | RESIDENT_COUNTY | resident_county | Major type 3 |
16 | HAZMAT_ENDORSEMENT_EXPIRATION_DATE | hazmat_endorsement_expiration_date | Major type 3 |
17 | DHS_TEMPORARY_LAWFUL_STATUS | DHS_temporary_lawful_status | Major type 0 |
Expected Results
QR code
Below are expected response from the sendRequest
API with the expected data type.
Data Fields | Data type/Unit | Sample Value |
---|---|---|
Namespace= "org.iso.18013.5.1" | ||
administrative_number | Text/String | "1234453" |
gender | Text/String | "M" |
height | Integer/Centimeter | "157" |
weight | Integer/Kg | "56" |
eye_color | Text/String | "BLU" |
hair_color | Text/String | "BLACK" |
birthplace | Text/String | "NY" |
resident_address | Text/String | "123, ABC Street" |
portrait_capture_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
age_in_years | Integer/String | "34" |
age_birth_year | Integer/String | "1978" |
age_over_NN | Boolean/String | "true" |
issuing_jurisdiction | Text/String | "NY" |
nationality | Text/String | "US" |
resident_city | Text/String | "NY" |
resident_state | Text/String | "NY" |
resident_postal_code | Text/String | "58773" |
name_nat_char | Text/String | "US" |
mgmt_nextupdate | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
family_name | Text/String | "Sample" |
given_name | Text/String | "Joe" |
birthdate | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
issue_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
expiry_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
issuing_country | Text/String | "US" |
issuing_authority | Text/String | "NY" |
document_number | Int/String | "782593823" |
portrait | ByteArray/Bytes | |
mgmt_lastupdate | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
mgmt_validity | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
driving_privileges | Text/String | [{"codes": [{"sign": "Sign","value": "value","code": "C"}],"issue_date": "2018-08-09","vehicle_category_code": "A","expiry_date": "2024-06-11"}] |
RealID | Boolean/String | true |
signature_usual_mark | ByteArray/Bytes | |
birth_date | DateTime/RFC3339 | "1985-04-12T23:20:50Z" |
birth_place | Text/String | "NY" |
name_national_character | Text/String | "US" |
given_name_national_character | Text/String | "US" |
family_name_national_character | Text/String | "US" |
Namespace = "org.iso.18013.1.aamva" | ||
DHS_compliance | Text/String | “F” = fully compliant “N” = non-compliant |
domestic_driving_privileges | Text/String | [{"domestic_vehicle_class": {"expiry_date": 0("2035-10-12 07:20:50.52Z"), "issuer_date": 0("2019-10-12 07:20:50.52Z"), "domestic_vehicle_class_code": "A", "domestic_vehicle_class_description": "vehicle category description"}, "domestic_vehicle_endorsements": [{"domestic_vehicle_endorsement_code": "E", "domestic_vehicle_endorsement_description": "vehicle endorsement description"}], "domestic_vehicle_restrictions": [{"domestic_vehicle_restriction_code": "C", "domestic_vehicle_restriction_description": "vehicle restrictions description"}]}] |
name_suffix | Text/String | “SR” |
organ_donor | Integer | 1 |
veteran | Integer | 1 |
family_name_truncation | Text/String | “N” |
given_name_truncation | Text/String | “N” |
aka_family_name.v2 | Text/String | “N” |
aka_given_name.v2 | Text/String | “S” |
aka_suffix | Text/String | “N” |
weight_range | Integer | “3” //Indicates the approxi- mate weight range of the credential holder: 0 = up to 31 kg; 1 = 32 – 45 kg ; 2 = 46 - 59 kg ; 3 = 60 - 70 kg |
race_ethnicity | Text/String | “A” //Codes for race or eth- nicity of the creden- tial holder, as defined in AAMVA D20. |
EDL_credential | Integer | 1 //This field is either absent or has one of the following values: 1: Driver’s license, 2: Identification card (Applicable only in the US. ) |
sex | Integer | 1 |
resident_county | Text/String | "107" //The 3-digit county code of the county where the credential holder lives, as per the 2010 FIPS Codes for Counties and County Equivalent Entitiesf. (Applicable only in the US. ) |
hazmat_endorsement_expiration_date | Text/String | "2024-01-11" |
DHS_temporary_lawful_status | Integer | 1 // This field is either absent or has value= 1: Temporary lawful status (Applicable only in the US. ) |
Deprecations and Deletions
- Deprecated APIs/Methods/Properties from previous versions are removed
ProGuard Rules
The following code snippets should be added in the app ProGuard Rules file.
- SDK obfuscation rules:
Language not specified1-keep public class idemia.verify.sdk.** {2 public protected *;3}4-keep class org.bouncycastle.**{*;}
Release Notes
- Refer CHANGELOG.md for full release notes history.
IACA certificate file format support
- Supports following formats for IACA certificates - (.pem, .crt, .der).
Elliptic Curve Support
Operation | Curve | Specification | Curve Identifier |
---|---|---|---|
ECDH/ECDSA | P-256 | FIPS-PUB 186-4 | IANA COSE Registry |
ECDH/ECDSA | P-384 | FIPS-PUB 186-4 | IANA COSE Registry |
ECDH/ECDSA | P-521 | FIPS-PUB 186-4 | IANA COSE Registry |
ECDH/ECDSA | brainpoolP521r1 | RFC 5639 | IANA COSE Registry |
ECDH/ECDSA | brainpoolP320r1 | RFC 5639 | IANA COSE Registry |
ECDH/ECDSA | brainpoolP384r1 | RFC 5639 | IANA COSE Registry |
ECDH/ECDSA | brainpoolP512r1 | RFC 5639 | IANA COSE Registry |
ECDH | X25519 | RFC 7748 | IANA COSE Registry |
ECDH | X448 | RFC 7748 | IANA COSE Registry |
EdDSA | Ed25519 | RFC 8032 | IANA COSE Registry |
EdDSA | Ed448 | RFC 8032 | IANA COSE Registry |
ISO-18013-5 Specification Support
ISO Version | Supported |
---|---|
N2448 (v1.1 Draft7) | Yes |
N1985 (published 1.0) | Yes |
N1938 | Yes |
N1818 | Yes |
N1677 | Yes |
Additions & Updates
- ISO Amendments N2448 (v1.1 Draft7):
- Device engagement implementation for with backwards compatibility support
- NFC Static+L2cap PSM functionality for mdoc Peripheral mode
- NFC Negotiated+L2cap PSM functionality for mdoc Peripheral mode
- NFC Negotiated+L2cap PSM functionality for mdoc Central mode
- ReaderAuthAll Implementation for N2448
- Implemented callback for downloading CRL data from the integrators application
- Compatible with Android 15 Beta (API level 35)
- Bug fixes and improvements
Error Codes
Error Code | Error Code Message | Description | Action Required |
---|---|---|---|
101 | Invalid QR Code | Unable to scan the QR code. | Please try again. |
102 | QR code parsing error | Unable to find some elements in the QR data item, Try again. | Try Again |
103 | QR code parsing error | DataItem(Map) is not found or empty, Unable to parse the QR code that the Mobile ID has provided. | Try again |
104 | QR code parsing error | DataItem(Array) not found or empty, Unable to parse the QR code that the Mobile ID has provided. | Try again |
105 | QR code scan error | Unable to Scan QR code may be because of invalid data or bad encoding | Try Again |
109 | Invalid cipher suite | Only cipher suite 1 (EC algorithm) is supported. | Try Again |
110 | Invalid EDeviceKey | mdoc ephemeral public point in the EDeviceKey in the DeviceEngagement structure sent by the mdoc is not on the indicated curve. | Try Again |
111 | Invalid EDeviceKey | Incorrect or unspecified curve Id, key type (kty) or x,y coordinates received in EDeviceKey DeviceEngagement structure sent by the mdoc | Try Again |
123 | Image Conversion Error | Error in convert image from bitmap to Image | Try again. |
141 | Nfc engagement error | Invalid NFC Tag, unable to read data | Try again |
142 | NFC handover error | Incorrect types for ac record,carrier record and auxiliary record | Try Again |
143 | NFC handover error | Reference length indicated longer than available bytes. | Try again |
144 | NFC handover error | Tag was lost, error during APDU transmission, tag may be out of field. | Try Again |
145 | ISO-DEP is not supported | Main Tag is not supporting ISO-DEP technology. | Try again |
146 | NFC handover error | Error with TT4 configuration | Try again |
147 | NFC handover error | Wrongly formatted Service Parameter record | Try again |
148 | NFC handover error | Error with Carrier Configuration record linking | Try again |
149 | NFC handover error | Main Initial message is null. | Try again |
150 | Nfc error - bad context | Bad context supplied - must be an Activity context | Pass the activity context in VSDKConfigs(activity) while creating VerifySDK Object, and try again |
151 | Nfc error - not enabled | NFC is not enabled. Go to settings and enable NFC | You may call VIDUtils.promptNfcSettings() to launch the NFC setting page or enable manually from setting |
152 | Nfc handover error | Error in NFC Handover, while getting NDEF TAG | |
201 | Unable to initialize BLE | Error in initializing BLE feature of this device. | The Mobile ID reader is not able to get BLE. The Mobile ID reader may abort the transaction. |
202 | Device Doesn't Support BLE | This device doesn't support the BLE feature. | The Mobile ID reader is not able to get BLE. The Mobile ID reader may abort the transaction. |
203 | BLE Scanning Error | Scanning of the BLE devices failed. | The Mobile ID reader is not able to scan the BLE devices. The Mobile ID reader may abort the transaction. |
204 | BLE connection Error | This device's Bluetooth is off. | The Bluetooth of the device is not enabled. The Mobile ID reader may abort the transaction. |
205 | BLE Scanning Error | Please provide the BLUETOOTH permissions | Try again |
206 | Connection Timeout | Unable to create communication channel with mDL device | Try again |
207 | BLE connection Error | An unexpected value exchanged during transmission | Try again |
208 | BLE Advertising Error | Failed to add BLE service | Try again |
209 | BLE L2CAP Error | Error while receiving response from mID | Try again |
210 | BLE L2CAP Error | Error while transferring request to mID | Try again |
212 | BLE Connection Error | Error in BLE state due to previous/indisposed connection(s) | |
221 | Connection mode not available | VerifySDK is not able to setup connection with Mobile ID using configured connection type/mode. | Try again |
281 | BLE Permission Error | Required permission BLUETOOTH_ADMIN not found in app AndroidManifest.xml | |
282 | Location Permission Error | Required permissions ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION not found in app AndroidManifest.xml | Please declare the required permissions in your app AndroidManifest.xml |
283 | Location Permission Error | Required permission ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION not granted | User must accept the permission when permission dialog is shown, check app permission settings to manually accept all required permissionsr |
284 | BLE Permission error | Required permission BLUETOOTH_CONNECT not found in app AndroidManifest.xml | android.permission.BLUETOOTH_CONNECT permission should be added in your app AndroidManifest.xml |
285 | BLE Permission error | Required permission BLUETOOTH_CONNECT not granted | User must accept the permission when permission dialog is shown, check app permission settings to manually accept all required permissions |
286 | BLE Permission error | Required permission BLUETOOTH_SCAN not found in app AndroidManifest.xml | android.permission.BLUETOOTH_SCAN permission should be added in your app AndroidManifest.xml |
287 | BLE Permission error | Required permission BLUETOOTH_SCAN not granted | User must accept the permission when permission dialog is shown, check app permission settings to manually accept all required permissions |
288 | BLE Permission error | Required permission BLUETOOTH_ADVERTISE not found in app AndroidManifest.xml | android.permission.BLUETOOTH_ADVERTISE permission should be added in your app AndroidManifest.xml |
289 | BLE Permission error | Required permission BLUETOOTH_ADVERTISE not granted | User must accept the permission when permission dialog is shown, check app permission settings to manually accept all required permissions |
290 | Error in connection | Can't create connection without device engagement. | initDeviceEngagement should be called before calling PrepareConnection |
291 | Error in connection | Connection terminated by client. | Call prepareConnection API to create new connection |
292 | Error in connection | Can't send request without prepareConnection. | prepareConnection api should be called before sendRequest |
301 | Transaction Cancelled | Transaction has been cancelled or closed. | Connection closed due to an error, try again. |
302 | Connection Lost | Unfortunately has device disconnected; device may be out of BLE/NaN.NFC range | The Mobile ID reader may abort the transaction. Try Again |
303 | Timed Out, Try again | Transaction has timeout or cancelled | Try Again |
304 | Request Incomplete. | Please select one or more attributes to be included in the request to the Mobile ID | Try Again |
305 | Incomplete Request | An Mobile ID comes to an end of data when expecting more data. For example, an Mobile ID expects certain length, number of arrays elements, or map entries but instead encounters the end of the data. The Mobile ID does not return any data but the error message. | The Mobile ID reader may abort the transaction. |
306 | Request Rejected | The Mobile ID indicates that the request is rejected. | BLE connection failure. he Mobile ID reader may abort the transaction. |
307 | The Mobile ID Reader Authentication Error | The Mobile ID indicates there is an error with Mobile ID Reader authentication | Try Again |
308 | General Error | The Mobile ID returns an error without any given reason. | The Mobile ID reader may inspect the request, ensure request is complete, and resend. The Mobile ID reader may abort the transaction. |
309 | Invalid Request | Request can't contain more than 2 age_over_nn as request attributes | Try Again |
310 | Error in reader authentication | callback or algorithm can not be null or empty | Try Again |
311 | Error in request data | Request params are null or invalid; Can't proceed | Try Again |
312 | Session Terminated by mDoc | SessionData status 20 is received from mDoc | Try Again |
400 | Error in response data received. | Response data is malformed or nil | Try Again |
401 | Parsing Error | An Mobile ID encountered data element that is not well-formed (e.g., invalid initial=byte) and failed decoding data. The Mobile ID does not return any data but the error message. | The Mobile ID reader may inspect the request, ensure request is complete, and resend. The Mobile ID reader may abort the transaction. |
402 | Invalid Format | The Mobile ID cannot process the requested data element due to a formatting error. | Try Again |
403 | Data Not Found | The requested NameSpace or data element within a NameSpace is not found. | Try Again |
404 | Data Request Denied | The release of requested data element was rejected by the Mobile ID holder. | Try Again |
405 | Data Not Returned | The Mobile ID does not provide the requested data element without any given reason. | Try Again |
406 | CBOR decoding Error | The Mobile ID indicates an error during CBOR decoding that the data received is not valid CBOR | Try Again |
407 | CBOR Validation Error | The Mobile ID indicates an error during CBOR validation, e.g. wrong CBOR structures | Try Again |
451 | Certificate Path Error | Either Path is invalid or inaccessible or not a folder path or folder is empty | Provide valid path and check required permissions to read/write the files are granted by user |
482 | IACA-DS validation Error | IACA-DS validation Error::Transaction not authenticated due to non-compliant or invalid DS or IACA certificate | Try Again! |
483 | Vical Loading Error | Error while loading vical file: [vicalFileName]. | Try Again! |
484 | License Authentication Failure | Vical file [vicalFileName] can’t be authenticated using given certificate: [vicalFileCertificate]. | Try Again! |
500 | Generic Error | Generic Error from VerifyID abstraction layer, concrete class must override to throw actual error | Try Again |
701 | Unable to discover Wi-Fi Aware service | Wi-Fi Aware Service is not discovered. | Try Again |
702 | Device Doesn't Support Wifi | This device does not support wifi feature. | Try Again |
703 | Wifi Aware Connection Timeout | Unable to establish socket connection, try again. | Try Again |
704 | WIFI is OFF | This device Wi-Fi is disabled, enable WiFi and try again. | Try Again |
705 | WiFi aware Network is Lost | Wifi aware connection network lost, try again | Try Again |
706 | Error in WiFi communication | Incorrect HTTP status code, expected 200 but found other. | Try Again |
751 | NFC data transfer error. | The Mobile ID Request is null or malformed | Try Again |
752 | NFC data transfer error | Response data is null or malformed, try again. | Try Again |
753 | NFC connection error | ISODep not connected; make sure to tap on back of other device to setup the NFC connection. | Try Again |
754 | NFC data transfer error | Error in receiving response from The Mobile ID, try again. | Try Again |
755 | NFC data transfer error | Error in NFC data transfer service, try again. | Try Again |
756 | NFC connection error | NFC hardware is disabled, Enable NFC from settings and try again. | Try Again |
757 | NFC connection error | NFC not supported as a system feature. | Try transfer mode other than NFC |
758 | NFC data transfer error | Tag was lost;Error during APDU NFC data transfer transmission,tag may be out of field | |
802 | Network Error | No internet connection available.Please turn on your internet connection and Try Again! | No internet connection available.Please turn on your internet connection and Try Again! |
801 | License Validation Failure | Some of the arguments are not right.Please check the arguments and Try Again! | Some of the arguments are not right.Please check the arguments and Try Again! |
803 | Network Error | Network connection lost while fetching data.Please check your internet connection and Try Again! | Network connection lost while fetching data.Please check your internet connection and Try Again! |
804 | Request Validation Failure | Request validation problem.Please check your request and Try Again! | Request validation problem.Please check your request and Try Again! |
805 | Server Error | Server error. Please wait for sometime! | License Server error.Please wait for sometime! |
806 | Bad Configurations | Error generating activation data on the server perhaps bad configuration.Please check your configurations and Try Again! | Error generating activation data on the server perhaps bad configuration.Please check your configurations and Try Again! |
807 | Bad Configurations | The specified resource is not available profile or apikey or both are invalid or that an unknown service exception happened.Try Again! | The specified resource is not available profile or apikey or both are invalid or that an unknown service exception happened.Try Again! |
808 | License Expired | Your license is expired.Please renew your license and Try Again! | Your license is expired.Please renew your license and Try Again! |
809 | License Validation Failure | Error while fetching data. License generic exception.Try Again! | Error while fetching data.License generic exception.Try Again! |
Test Samples
QR + BLE Sample
The following screen shows a scan of the QR code in the Mobile ID App.
Note: This screenshot is only for device engagement QR code testing. The full QR + BLE scenario will only work with a real device with the IDEMIA Mobile ID App installed.