EKYC-ANDROID

Compatibility & Lib Size

This version is compatible with Android SDK 28+ (Android 9+) .

Library Lib will add around ~14MB to your application in App Bundle mode (The real download size on Google Play Store)


LiveNess License

To make the LiveNess feature work, EkycSDK check the app License based on the Android package name, so please contact our support team to support the new package name.

If POC, please use com.ekyc.sdk.* format as your test project Package name


Current Version

Mac EKYC Core: 1.9.2

Mac EKYC LiveNess: 9.6.72

Releases Notes


SDK Integration

Setup SDK dependency

Add AppMan maven repo

To connect with the AppMan repository, add this maven configuration in root/build.gradle with the aws access/secret keys

Old Bucket

allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
            url "s3://agm-android"
            credentials(AwsCredentials) {
                accessKey aws_access_key
                secretKey aws_secret_key
            }
        }
    }
}

New Bucket

allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
            url "s3://ekyc-sdk-prod"
            credentials(AwsCredentials) {
                accessKey aws_access_key
                secretKey aws_secret_key
            }
        }
    }
}

Implement ekyc native dependency

  1. Implement Ekyc SDK dependency in app module app/build.gralde in dependencies

implementation "appman:mac-ekyc-core:ekyc-core-version"
implementation "appman:mac-ekyc-liveness-ft:ekyc-liveness-version"

  1. Example.
dependencies {
    implementation "appman:mac-ekyc-core:1.8.3"
    implementation "appman:mac-ekyc-liveness-ft:9.6.72"
}    

Ekyc SDK require mac-ekyc-core & mac-ekyc-liveness-ft module

Setup Permission NFC

Add permission for using NFC in file AndroidManifest.xml

<manifest> <uses-permission android:name="android.permission.NFC"/> </manifest>

But if you don't want to use NFC, Please add this in the file AndroidManifest.xml

<manifest> <uses-permission android:name="android.permission.NFC" tools:node="remove"/> </manifest>

Usage

Start EKYC process

Ekyc SDK required parameters

To start Ekyc SDK, we need setup EkycConfig object with these parameters (All is required)

- Production environment

ekycConfig = EkycConfig( clientName = "{{clientName}}", ekycServiceURL = "https://mac-portal.appmanteam.com/api/{{version}}/kyc", tenantServiceURL = "https://mac-portal.appmanteam.com/api/v1/tenant-config", ekycSiteURL = "https://{{clientName}}.mac.appmanteam.com/apps/identity-verification", verificationId = "{{verificationID}}", language = Language.THAI, // Default is ENGLISH if don't change this parameter, emulatorMode = false, // Deprecated. Please always set false enableManualCaptureMode = false // Default is false, SDK will using ML and auto capture // when detected IDCard frame (Both Normal/ Hologram mode) )

enableManualCaptureMode

if you are using auto capture for ocr, and want to disable auto capture you can set enableManualCaptureMode to true.

ekycConfig = EkycConfig( ..., enableManualCaptureMode = true // Default is false. )

Ekyc SDK Security

This sdk already implement Google play integrity for use with application that upload to Googleplay store.

you need to config on Google play store for enable AppIntegrity, then change setting to use self-management for encryption and decryption.

GCP_ID : is Google cloud project that you link to google play store

DECRYPTION_KEY and VERIFICATION_KEY : is decryption key from setting on google play store.

ekycFragment = EkycMainFragment() ekycFragment.setupGooglePlayIntegrity(GCP_ID, DECRYPTION_KEY, VERIFICATION_KEY) // this on is optional if you not set it turn off by default.

Embed MainEkycFragment

For next step, init EkycMainFragment and embed in your ViewGroup holder and start Ekyc Process

ekycFragment = EkycMainFragment() ekycFragment.setupEkycConfiguration(ekycConfig) supportFragmentManager.beginTransaction().apply { add(R.id.ekycNativeFragment, ekycFragment, fragmentTag) .commit() } ekycFragment.startEkyc()

Progagate LiveNess return data

On LiveNess flow, the result data is turned back to EkycSDK through onActivityResult, we need to add the below block code in your MainActivity to propagate this data to EkycMainFragment for further processing

If we create new EkycMainFragment instance with a local variable

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) // // Find the Ekyc Fragment by Tag Name "EkycFragment" and propagate event to it supportFragmentManager.findFragmentByTag(fragmentTag)?.let { it.onActivityResult(requestCode, resultCode, data) } }

fragmentTag is the Tag Name we using to identify EkycMainFragment when add to Activity

supportFragmentManager.beginTransaction().apply { add(R.id.ekycNativeFragment, ekycFragment, fragmentTag) .commit() }

EKYC Listener

All EKYC events will be notified through theEkycMainFragment.ekycListener.

ekycFragment.ekycListener = object : EkycListener { override fun onEkycStarted() { TODO("Not yet implemented") } override fun onEkycStoped() { TODO("Not yet implemented") } override fun onEkycStatus(ekycStatus: EkycStatus) { TODO("Not yet implemented") } override fun onEkycError(ekycError: EkycError) { TODO("Not yet implemented") } }

Ekyc Stopped Stoped event

The onEkycStarted event will be notified after startEkyc() is called without any setup error

The onEkycStoped event will be notified if the fragment is detached from Activity

Tracking Ekyc status

Ekcy SDK will notify the Ekyc Status includes: completed, expired, verified, retry through onEkycStatus(ekycStatus: EkycStatus) function when perform Ekyc Process.

📘

Verified status

This status will be notified in these cases

  • User completely finish the last step of EKYC with all steps passed

  • Start EKYC process with VerificationID already verified

📘

Completed status

This status will be notified in these cases

  • After the user finished the the last EKYC step but some of the verification not passed such as: LiveNess, DOPA
  • Start EKYC process with VerificationID already completed

📘

Expired status

  • Start EKYC process with VerificationID what already expired, can not continue this EKYC case

📘

Retry status

  • This retry event will be possible to happen only if your application config have the bypass overlay feature enabled.

  • When creating EKYC verifications, set frontIdCardConfig.dependenciesRequired to false

  • In the verification steps such as front ID Card, back ID card, passport, etc. if we input wrong information and click confirm, this "bypass overlay" will be displayed

  • In case we click on EDIT button, this status will be notified

Handle Ekyc Error cases

We support following error cases in Ekyc SDK (The Error is one instance of EkycError)

  1. EKYCAlreadyStarted

    If we call startEkyc() while the Ekyc SDK already started

  2. MissingConfiguration

    If we missing any parameter of EkycConfig, this error also notify the configurationName to pointed out which param is missing

override fun onEkycError(error: EkycError) { when (error) { is EkycError.MissingConfiguration -> { log("onEkycError MissingConfiguration ${error.configurationName}") } is EkycError.EKYCAlreadyStarted -> { log("onEkycError EKYCAlreadyStarted") } } }
  1. SSLPiningError

    Trigger when SSLPining not passed

onEkycError(SSLPiningError)
  1. SecurityError

    This error also include which EKYCSecurityItem not passed when do Security Check

onEkycError(EKYCSecurityItem)
  1. CameraBindingError

    Can not setup device Camera, a device with a broken camera or emulator does not support camera

onEkycError(CameraBindingError)
  1. CameraCaptureError

    Can not capture pictures with an unknown issue

onEkycError(CameraCaptureError)

Restart SDK

To Restart EKYC SDK (Load another Ekyc Link), just simply remove the EkycMainFragment from activity and attach it again.

if (supportFragmentManager.findFragmentByTag(fragmentTag) != null) { supportFragmentManager.beginTransaction().apply { remove(ekycFragment) .commit() } }

Emulator mode (Deprecated)

Emulator mode allow by pass some Ekyc steps to do testing on Emulator, enable EkycConfig.emulatorMode before start Ekyc to bypass following steps

  • FrontIDCard OCR
  • BackIDCard OCR
  • Passport with OCR
  • Passport with NFC
  • LiveNess checking

In Emulator mode, SDK will return Mock data immediately when start above steps

    ekycFragment.turnOffStartKoinProcess() 

    supportFragmentManager.beginTransaction().apply {
        add(R.id.ekycNativeFragment, ekycFragment, fragmentTag)
            .commit()
    }

    ekycFragment.startEkyc()

Start LiveNess Match Checker process

EkycSDK also supports doing the LiveNess process only to recheck the Liveness with the current EKYC result

LiveNess required parameters

To start the liveness process, we need setup EkycConfig object with these parameters (All is required)

- Production environment

ekycConfig = EkycConfig( clientName = "{{clientName}}", ekycServiceURL = "https://mac-portal.appmanteam.com/api/v2/kyc", tenantServiceURL = "https://mac-portal.appmanteam.com/api/v1/tenant-config", ekycSiteURL = "https://{{clientName}}.mac.appmanteam.com/apps/identity-verification", verificationId = "{{verificationID}}", language = Language.THAI // Default is ENGLISH if don't change this parameter, emulatorMode = false // Deprecated. Please always set false )

Liveness Securities

LiveNess standalone process also supports Security stuff by turning on setup Google Play Integrity same as bellow

LiveNessMatchChecker.setupGooglePlayIntegrity(GCP_ID, DECRYPTION_KEY, VERIFICATION_KEY) // this on is optional if you not set it turn off by default.

Start Liveness Match Checker

For next step, call the start function in LiveNessMatchChecker

LiveNessMatchChecker.start(context = this, ekycConfig = ekycConfig, liveLessCompareListener = this)

Liveness Listener

All Liveness events will be notified through theLiveNessMatchChecker.livenessCompareListener.

LiveNessMatchChecker.livenessCompareListener = object : LiveLessCompareListener { override fun onLiveNessStarted() { TODO("Not yet implemented") } override fun onLiveNessError(liveNessMatchError: LiveNessMatchError) { TODO("Not yet implemented") } override fun onLiveNessStatus(liveNessMatchStatus: LiveNessMatchStatus) { TODO("Not yet implemented") } }

Liveness Started event

The onLiveNessStarted event will be notified after LiveNessMatchChecker.start() is called without any setup error

Liveness Status event

Notify the Liveness Status includes: Completed, UserCancel through onLiveNessStatus(liveNessMatchStatus: LiveNessMatchStatus).

📘

Completed Status

This status will be notified in these cases

  • User completely finish the liveness 3d compare

📘

UserCancel status

This status will be notified in these cases

  • User close liveness screen without finish liveness

Liveness Error event

We support following error cases in Liveness SDK (The Error is one instance of LiveNessMatchError)

  1. MissingConfiguration

    If we missing any parameter of EkycConfig, this error also notify the configurationName to pointed out which param is missing

LiveNessMatchChecker.livenessCompareListener = object : LiveLessCompareListener { override fun onLiveNessError(liveNessMatchError: LiveNessMatchError) { when(liveNessMatchError) { is LiveNessMatchError.MissingConfiguration -> { log("onLiveNessError MissingConfiguration ${liveNessMatchError.configurationName}") } } } }
  1. SSLPiningError
    Trigger when SSLPining not passed
onLiveNessError(SSLPiningError)
  1. SecurityError
    This error also include which EKYCSecurityItem not passed when do Security Check
onLiveNessError(SecurityError)
  1. TenanConfigError
    Trigger when get tanant config failed
onLiveNessError(TenanConfigError)
  1. GetCredentialsError
    Trigger when get credentials failed
onLiveNessError(GetCredentialsError)
  1. LivenessSetupError
    Trigger when can't initialize liveness SDK
onLiveNessError(LivenessSetupError)
  1. CannotGetLiveNessToken
    Trigger when get token liveness fail
onLiveNessError(CannotGetLiveNessToken)
  1. EkycMissing
    Trigger when missing liveness from EKYC flow. Should be finish EKYC before do liveness match checker.
onLiveNessError(EkycMissing)
  1. OSNotSupport
    Trigger when SDK not support that OS version.
onLiveNessError(OSNotSupport)
  1. UnknownError
    Trigger when get other error with error message
LiveNessMatchChecker.livenessCompareListener = object : LiveLessCompareListener { override fun onLiveNessError(liveNessMatchError: LiveNessMatchError) { when(liveNessMatchError) { is LiveNessMatchError.UnknownError -> { log("onLiveNessError UnknownError ${liveNessMatchError.msg}") } } } }

SDK Securities

SDK using SSLPining to prevent Man In The Middle attach for Ekyc/Liveness module, if application using Proxy, SDK will throw onEkycError(SSLPiningError) when starting.

ESDK also detect some Security stuff before Start Ekyc process, includes

  1. Check UnTrused device using SafetyNet service
  2. Detect Rooted device
  3. Detect app run in debug mode

Prefer to enum class EKYCSecurityItem for default of Security Checking item.

enum class EKYCSecurityItem(val code: Int, val subCode: Int) { NO_DETECTION(0, 0), SAFETY_NET(1, 0), // Detect Root Apps Package ROOT(2, 0), // Detect Root Apps Package ROOT_APP_PACKAGE(2, 1), // Another Dangerous app package ROOT_DANGEROUS_APP(2, 2), // Check whether binary Root program exist ROOT_APP_PATH(2, 3), // Check whether related Root app paths exist ROOT_RELATED_APP(2, 4), // Check binary app using which command ROOT_BINARY(2, 5), // Check rw permission on system paths ROOT_PROTECTION_PATH(2, 6), // Check BUILD tag for test-keys ROOT_TEST_KEY(2, 7), // Over The Air (OTA) certs ROOT_OTA_CERTS(2, 8), // JDWP Anti-Debugging DEBUG(3, 0), // Check debug flag via ApplicationInfo DEBUG_FLAG(3, 1), // Check debugger connected via android.os.Debug [DEBUG_DETECT_DEBUGGER], // Check slow CPU calculation in debug mode DEBUG_SLOW_CPU(3, 3) }

Skip Security Debug Mode case in EKYC process

To skip any Security Check Debug case before Start Ekyc, using EkycMainFragment.turnOffSecurityDebug()

For example When develop application, we might run app in debug mode, add a bellow code block to make EkycSDK ignore checking debug

if (BuildConfig.DEBUG) ekycFragment.turnOffSecurityDebug() ekycFragment.startEkyc()

Skip Security Debug Mode case in LiveNess Match Checker process

To skip any Security Check item before Start Liveness, using
LiveNessMatchChecker.turnOffSecurityDebug()

For example When develop application, we might run app in debug mode, add a bellow code block to make EkycSDK ignore checking debug

if (BuildConfig.DEBUG) { LiveNessMatchChecker.turnOffSecurityDebug() } LiveNessMatchChecker.start(this, ekycConfig, liveLessCompareListener = this)

Third-party libraries

EkycSDK also uses third-party libraries to build its feature, these are some libraries inside and their versions

NamePackageVersion
Android General Libsandroidx.core:core-ktx1.9.0
androidx.appcompat:appcompat1.5.1
androidx.constraintlayout:constraintlayout2.0.1
Android Composeandroidx.compose.runtime:runtime-livedata1.3.1
androidx.compose.animation:animation-graphics1.3.2
androidx.compose.material3:material31.0.1
androidx.compose.ui:ui-tooling1.3.1
androidx.compose.ui:ui-tooling-preview1.3.1
androidx.activity:activity-compose1.5.1
androidx.lifecycle:lifecycle-viewmodel-compose2.5.1
com.google.accompanist:accompanist-permissions0.28.0
com.google.accompanist:accompanist-systemuicontroller0.28.0
Android CameraXandroidx.camera:camera-lifecycle1.2.0
androidx.camera:camera-video1.2.0
androidx.camera:camera-view1.2.0
androidx.camera:camera-extensions1.2.0
Logger Analyticsio.sentry:sentry-android5.6.2
com.flurry.android:analytics14.0.0
ML, Tensorflowcom.google.mlkit:object-detection16.2.4
org.tensorflow:tensorflow-lite2.8.0
org.tensorflow:tensorflow-lite-support0.3.1
org.tensorflow:tensorflow-lite-metadata0.3.1
Google Servicescom.google.android.gms:play-services-location21.0.1
NFC Supportorg.jmrtd:jmrtd0.7.36
net.sf.scuba:scuba-sc-android0.0.24
com.madgag.spongycastle:prov1.54.0.0
com.github.mhshams:jnbis1.1.0
Network Handlingcom.squareup.retrofit2:retrofit2.9.0
com.squareup.retrofit2:converter-gson2.9.0
com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter0.9.2
com.squareup.okhttp3:okhttp4.9.2
com.squareup.okhttp3:logging-interceptor4.9.2
Unsynchronized processingorg.jetbrains.kotlinx:kotlinx-coroutines-core1.3.7
org.jetbrains.kotlinx:kotlinx-coroutines-android1.3.7
Image Processingio.coil-kt:coil-compose2.2.2
io.coil-kt:coil-svg2.2.2
Othersorg.jetbrains.kotlin:kotlin-reflect1.7.21
commons-io:commons-io2.8.0

Example Project

Refer to this Example App to see how EkycSDK work

git clone https://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@github.com/appman-agm/mac-identity-verification-android-example.git

FAQs

Integration Issues

Q: How Can I resolve **Duplicate class kotlin** when integrating SDK?

In some cases, we can face this issue which caused by the following reason

When you add multiple dependencies to your app project, those direct and transitive dependencies might conflict with one another. The Android Gradle plugin tries to resolve these conflicts gracefully, but some conflicts may lead to compile time or runtime errors.

Refer to this article for more detail: https://developer.android.com/build/dependencies#resolution_errors

👍

A:

To resolve this, we can try the following ways

The below script tells the build tool that let pick org.bouncycastle:bcprov-jdk15to18:1.68 if found confliction in group org.bouncycastle

android {
. . . 
configurations.all {
        c -> c.resolutionStrategy.eachDependency {
            DependencyResolveDetails dependency ->
                if (dependency.requested.group == 'org.bouncycastle') {
                    dependency.useTarget 'org.bouncycastle:bcprov-jdk15to18:1.68'
                }
        }
    }
}

Using exclude command when implementing dependency. Below script will exclude the module lifecycle-viewmodel-ktx when implement koin module

    implementation ("io.insert-koin:koin-android:$koin_version") {
        exclude group: "androidx.lifecycle", module: "lifecycle-viewmodel-ktx"
    }

Did this page help you?