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
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
- Implement Ekyc SDK dependency in
app
moduleapp/build.gralde
independencies
implementation "appman:mac-ekyc-core:ekyc-core-version"
implementation "appman:mac-ekyc-liveness-ft:ekyc-liveness-version"
- 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
tofalse
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
)
-
EKYCAlreadyStarted
If we call
startEkyc()
while the Ekyc SDK already started -
MissingConfiguration
If we missing any parameter of
EkycConfig
, this error also notify theconfigurationName
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")
}
}
}
-
SSLPiningError
Trigger when SSLPining not passed
onEkycError(SSLPiningError)
-
SecurityError
This error also include which EKYCSecurityItem not passed when do Security Check
onEkycError(EKYCSecurityItem)
-
CameraBindingError
Can not setup device Camera, a device with a broken camera or emulator does not support camera
onEkycError(CameraBindingError)
-
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
)
-
MissingConfiguration
If we missing any parameter of
EkycConfig
, this error also notify theconfigurationName
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}")
}
}
}
}
- SSLPiningError
Trigger when SSLPining not passed
onLiveNessError(SSLPiningError)
- SecurityError
This error also include whichEKYCSecurityItem
not passed when do Security Check
onLiveNessError(SecurityError)
- TenanConfigError
Trigger when get tanant config failed
onLiveNessError(TenanConfigError)
- GetCredentialsError
Trigger when get credentials failed
onLiveNessError(GetCredentialsError)
- LivenessSetupError
Trigger when can't initialize liveness SDK
onLiveNessError(LivenessSetupError)
- CannotGetLiveNessToken
Trigger when get token liveness fail
onLiveNessError(CannotGetLiveNessToken)
- EkycMissing
Trigger when missing liveness from EKYC flow. Should be finish EKYC before do liveness match checker.
onLiveNessError(EkycMissing)
- OSNotSupport
Trigger when SDK not support that OS version.
onLiveNessError(OSNotSupport)
- 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
- Check UnTrused device using
SafetyNet
service - Detect Rooted device
- 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
Name | Package | Version |
---|---|---|
Android General Libs | androidx.core:core-ktx | 1.9.0 |
androidx.appcompat:appcompat | 1.5.1 | |
androidx.constraintlayout:constraintlayout | 2.0.1 | |
Android Compose | androidx.compose.runtime:runtime-livedata | 1.3.1 |
androidx.compose.animation:animation-graphics | 1.3.2 | |
androidx.compose.material3:material3 | 1.0.1 | |
androidx.compose.ui:ui-tooling | 1.3.1 | |
androidx.compose.ui:ui-tooling-preview | 1.3.1 | |
androidx.activity:activity-compose | 1.5.1 | |
androidx.lifecycle:lifecycle-viewmodel-compose | 2.5.1 | |
com.google.accompanist:accompanist-permissions | 0.28.0 | |
com.google.accompanist:accompanist-systemuicontroller | 0.28.0 | |
Android CameraX | androidx.camera:camera-lifecycle | 1.2.0 |
androidx.camera:camera-video | 1.2.0 | |
androidx.camera:camera-view | 1.2.0 | |
androidx.camera:camera-extensions | 1.2.0 | |
Logger Analytics | io.sentry:sentry-android | 5.6.2 |
com.flurry.android:analytics | 14.0.0 | |
ML, Tensorflow | com.google.mlkit:object-detection | 16.2.4 |
org.tensorflow:tensorflow-lite | 2.8.0 | |
org.tensorflow:tensorflow-lite-support | 0.3.1 | |
org.tensorflow:tensorflow-lite-metadata | 0.3.1 | |
Google Services | com.google.android.gms:play-services-location | 21.0.1 |
NFC Support | org.jmrtd:jmrtd | 0.7.36 |
net.sf.scuba:scuba-sc-android | 0.0.24 | |
com.madgag.spongycastle:prov | 1.54.0.0 | |
com.github.mhshams:jnbis | 1.1.0 | |
Network Handling | com.squareup.retrofit2:retrofit | 2.9.0 |
com.squareup.retrofit2:converter-gson | 2.9.0 | |
com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter | 0.9.2 | |
com.squareup.okhttp3:okhttp | 4.9.2 | |
com.squareup.okhttp3:logging-interceptor | 4.9.2 | |
Unsynchronized processing | org.jetbrains.kotlinx:kotlinx-coroutines-core | 1.3.7 |
org.jetbrains.kotlinx:kotlinx-coroutines-android | 1.3.7 | |
Image Processing | io.coil-kt:coil-compose | 2.2.2 |
io.coil-kt:coil-svg | 2.2.2 | |
Others | org.jetbrains.kotlin:kotlin-reflect | 1.7.21 |
commons-io:commons-io | 2.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
- Inspect
view-dependency-tree
and apply some solutions in this article https://developer.android.com/build/dependencies#view-dependency-tree- Add build script config to resolve classpaths confliction. These are some example scripts
The below script tells the build tool that let pick
org.bouncycastle:bcprov-jdk15to18:1.68
if found confliction in grouporg.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 modulelifecycle-viewmodel-ktx
when implementkoin
moduleimplementation ("io.insert-koin:koin-android:$koin_version") { exclude group: "androidx.lifecycle", module: "lifecycle-viewmodel-ktx" }
Updated 3 months ago