Android
The following guide will get you started with the Android SDK for Incode Onboarding.
Minimum hardware requirements
Ram: 3GB Back-facing camera: 5MP Front-facing (selfie) camera: 2MP
Installation
Important: Distribution through Artifactory will no longer be supported after September 19th, 2025. If you are currently using Artifactory in your production integration, you must complete the migration to GitHub Packages before this date to ensure uninterrupted access to the SDK.
The Incode Omni Android SDK is distributed through GitHub Packages. To receive credentials for the SDK, please reach out to your enterprise customer success manager or request your GitHub access token via our Help Desk:[email protected].
Add the following GitHub packages credentials to your project dependencies. Read the Gradle documentation about declaring dependencies for more information.
repositories {
maven {
url "https://maven.pkg.github.com/Incode-Technologies-Example-Repos/android-omni-packages"
credentials {
username = "incode-customers"
password = "GITHUB_TOKEN"
}
}
}repositories {
maven {
url = uri("https://maven.pkg.github.com/Incode-Technologies-Example-Repos/android-omni-packages")
credentials {
username = "incode-customers"
password = "GITHUB_TOKEN"
}
}
}The Incode SDK is dependent on jitpack. Add the following maven repository:
repositories {
maven { url "https://jitpack.io" }
}repositories {
maven("https://jitpack.io")
}Finally, ensure Google and Maven Central are included in the file:
repositories {
google()
mavenCentral()
}repositories {
google()
mavenCentral()
}The dependencies should look like the following:
repositories {
google()
mavenCentral()
maven { url "https://jitpack.io" }
maven {
url "https://repo.incode.com/artifactory/libs-incode-welcome"
credentials {
username = "organizationUsername"
password = "xxxxxxxxxxxxxxxxxxxx"
}
}
}repositories {
google()
mavenCentral()
maven("https://jitpack.io")
maven {
url = uri("https://repo.incode.com/artifactory/libs-incode-welcome")
credentials {
username = "organizationUsername"
password = "xxxxxxxxxxxxxxxxxxxx"
}
}
}In your module-level app/build.gradle, we require a minimum of Java 8 for both source and targetCompatibility. To enforce this, add the following code inside your android{} block:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}Next, in your app/build.gradle, add Incode library dependencies as described below.
Dependencies
The Incode Omni Android SDK has several library dependencies. Core dependencies must be included. Optional ones should be added as needed based on the use case. These are explained below:
dependencies {
...
// Incode Omni SDK
implementation 'com.incode.sdk:welcome:5.41.0' // Required core dependency
implementation 'com.incode.sdk:core-light:3.0.5' // Required core dependency
// The following dependencies are optional and needed only in very specific use cases.
// Make sure you are using the features they provide before adding the dependencies below.
implementation 'com.incode.sdk:extensions:1.2.1' // Optional dependency
implementation 'com.incode.sdk:nfc:1.5.0' // Optional dependency
implementation 'com.incode.sdk:video-streaming:1.6.0' // Optional dependency
implementation 'com.incode.sdk:model-face-recognition:3.5.1' // Optional dependency
implementation 'com.incode.sdk:model-id-face-detection:3.5.1' // Optional dependency
implementation 'com.incode.sdk:model-liveness-detection:3.2.1' // Optional dependency
}dependencies {
...
// Incode Omni SDK
implementation("com.incode.sdk:welcome:5.41.0") // Required core dependency
implementation("com.incode.sdk:core-light:3.0.5") // Required core dependency
// The following dependencies are optional and needed only in very specific use cases.
// Make sure you are using the features they provide before adding the dependencies below.
implementation("com.incode.sdk:extensions:1.2.1") // Optional dependency
implementation("com.incode.sdk:nfc:1.5.0") // Optional dependency
implementation("com.incode.sdk:video-streaming:1.6.0") // Optional dependency
implementation("com.incode.sdk:model-face-recognition:3.5.1") // Optional dependency
implementation("com.incode.sdk:model-id-face-detection:3.5.1") // Optional dependency
implementation("com.incode.sdk:model-liveness-detection:3.2.1") // Optional dependency
}Core dependencies
-
welcomedependency: the main module of the entire Incode Omni SDK. It contains all the core functionality of the SDK. -
core-lightdependency: contains the image processing libraries used in the Omni SDK.
Optional dependencies
-
cameradependency: only necessary when using theSelfieScanmodule on the-nuline of releases. -
extensionsdependency: only necessary for using a custom Theme Configuration, Dynamic Localization, or Runtime Localization. -
nfcdependency: only necessary if you are using theNfcScanmodule of the SDK. Additional configuration is also required, as described in the NFC Scan - Integration & Usage Guide. -
video-streamingdependency: only necessary if you are using theConferencemodule or thestreamFramesfeature in theIdScanorSelfieScanmodules. -
model-face-recognitiondependency: only necessary if you are using the face recognition feature that runs locally on the device. This feature is only available for Face Login. -
model-id-face-detectiondependency: only necessary if you are using checks to detect the front/back side of an ID. -
model-liveness-detectiondependency: only necessary if you are using the liveness detection feature that runs locally on the device.
Building
After adding all necessary dependencies, do a test build of the project. If you encounter issues during the build process, refer to the troubleshooting section.
If the build is successful, you can begin integration.
Required permissions
Our manifest files declare the following permissions:
com.incode.sdk:welcome
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />com.incode.sdk:nfc
<uses-permission android:name="android.permission.NFC" />If your application does not utilize the screen recording features of the IdScan, SelfieScan, or VideoSelfie modules, you can safely exclude foreground service permissions by adding the following block in your application AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" tools:node="remove" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" tools:node="remove" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" tools:node="remove" />Optional permissions
Some SDK functions can be enhanced with additional permissions. These enhancements may or may not be right for your app or use case.
Note that using these permissions will subject your app to additional scrutiny when publishing on Google Play. It's recommended to only utilize these optional permissions if your app already has a different use case for them.
Querying all apps on the device on Android 11+
When the Incode Omni SDK performs root detection, it can take more actions to find evidence of a rooted device by adding the following permission:
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />By default on Android 11+, the root detection algorithm will skip over any action that requires the QUERY_ALL_PACKAGES permission if it's not present. This can lead to some rooted devices being undetected. Below Android 11, any actions that required the QUERY_ALL_PACKAGES permission on Android 11+ will be taken by the root detection algorithm.
Higher sampling rates on Android 12+
When determining the device's motionStatus for IdScan and SelfieScan, the sampling rate used can be maxed out by adding the following permission:
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />By default on Android 12+, the second highest sample rate available will be used when determining the device's motionStatus. Below Android 12, using the highest sampling rate is automatic.
Troubleshooting
Attribute application@allowBackup value=(true) from AndroidManifest.xml
Attribute application@allowBackup value=(true) from AndroidManifest.xml is also present at [com.incode.sdk:welcome:x.x.x] AndroidManifest.xml value=(false).
Suggestion: add 'tools:replace="android:allowBackup"' to `<application>` element at AndroidManifest.xml to override.
Solution
This means that you have set allowBackup in your AndroidManifest.xml to true, but the Welcome SDK has this value set to false. Having allowBackup set to true is a potential security issue, so we suggest setting it to false. If you are sure that you wish to allow backups, then add tools:replace="android:allowBackup" to <application> element in your AndroidManifest.xml. If you already have some attributes in tools:replace, separate them with commas (for example: "android:label,android:allowBackup").
Static interface methods are only supported starting with Android N
Static interface methods are only supported starting with Android N (--min-api 24): Lbutterknife/Unbinder;lambda$static$0()V
Error while dexing. The dependency contains Java 8 bytecode. Please enable desugaring by adding the following to build.gradle
android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}}
Solution
In your module-level [module]/build.gradle, add the following code to android{} closure:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}All modules with native libraries must support the same set of ABIs
Execution failed for task ':app:packageDebugBundle'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> All modules with native libraries must support the same set of ABIs, but module 'base' supports '[X86, ARMEABI_V7A, ARM64_V8A, X86_64, MIPS, ARMEABI]' and module 'incode_core' supports '[ARMEABI_V7A, X86, X86_64, ARM64_V8A]'.
- problem when generating bundles.
Solution
Add the following ndk abi filters to your module-level app/build.gradle inside defaultConfig{} closure:
ndk {
abiFilters "arm64-v8a", "armeabi-v7a", "x86", "x86_64"
}ndk {
abiFilters.add("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
}FATAL EXCEPTION: RxCachedThreadScheduler
E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-2
Process: com.incode.welcome.example, PID: 6842
io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.lang.NoSuchMethodError: No virtual method log(ILjava/lang/String;Ljava/lang/Throwable;)V in class Lokhttp3/internal/platform/Platform; or its super classes (declaration of 'okhttp3.internal.platform.Platform' appears in /data/app/com.incode.welcome.example-HnCVs4pdPTZBq3BhFsJmdQ==/base.apk!classes3.dex)
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:69)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: java.lang.NoSuchMethodError: No virtual method log(ILjava/lang/String;Ljava/lang/Throwable;)V in class Lokhttp3/internal/platform/Platform; or its super classes (declaration of 'okhttp3.internal.platform.Platform' appears in /data/app/com.incode.welcome.example-HnCVs4pdPTZBq3BhFsJmdQ==/base.apk!classes3.dex)
at okhttp3.logging.HttpLoggingInterceptor$Logger$1.log(HttpLoggingInterceptor.java:114)
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:173)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:148)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:186)
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:45)
at io.reactivex.Observable.subscribe(Observable.java:12267)
at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
at io.reactivex.Observable.subscribe(Observable.java:12267)
at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:32)
at io.reactivex.Observable.subscribe(Observable.java:12267)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Solution
This crash occurs when the okhttp3:okhttp dependency version is different from okhttp3:logging-interceptor or okhttp3:okhttp-urlconnection dependencies and trying to initialize Incode SDKs.
For example, if you have the following dependencies in the Project's External Libraries, you will face the crash because of the version inconsistency:
okhttp3:logging-interceptor:3.4.1okhttp3:okhttp-urlconnection:3.4.1okhttp3:okhttp:4.5.0
To fix the crash, for the example above, you need to bump the version of okhttp3:logging-interceptor & okhttp3:okhttp-urlconnection to 4.5.0.
Add the following implementations inside build.gradle to override existing lower versions:
dependencies {
...
implementation 'com.squareup.okhttp3:logging-interceptor:4.5.0'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.5.0'
}
It is important to note that the crash will still occur in the case you only have the logging-interceptor or okhttp-urlconnection dependency.
Crashes if you have in External Libraries these dependencies:
okhttp3:logging-interceptor:3.4.1okhttp3:okhttp:4.5.0
Crashes as well if you have in External Libraries these dependencies:
okhttp3:okhttp-urlconnection:3.4.1okhttp3:okhttp:4.5.0
InvalidUserCodeException: Build was configured to prefer settings
org.gradle.api.InvalidUserCodeException: Build was configured to prefer settings repositories over project repositories but repository 'maven' was added by build file 'build.gradle'
Solution
For projects using Gradle 6.8 or higher, a new way of defining dependencies in settings.gradle with the dependencyResolutionManagement block was introduced. Moving the maven repo declaration from the project build.gradle to here should resolve it. See also StackOverflow.
dependencyResolutionManagement {
...
repositories {
...
maven {
url "https://repo.incode.com/artifactory/libs-incode-welcome"
credentials {
username = "organizationUsername"
password = "xxxxxxxxxxxxxxxxxxxx"
}
}
}
}dependencyResolutionManagement {
...
repositories {
...
maven {
url = uri("https://repo.incode.com/artifactory/libs-incode-welcome")
credentials {
username = "organizationUsername"
password = "xxxxxxxxxxxxxxxxxxxx"
}
}
}
}A problem occurred evaluating root project
Build was configured to prefer settings repositories over project repositories but repository 'Google' was added by build file 'build.gradle'
Solution
In the settings.gradle file, ensure that the repositoriesMode is set to RepositoriesMode.PREFER_PROJECT
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
repositories {
google()
mavenCentral()
}
}
Sentry Compatibility Issues
Since version 5.24.0, the Incode SDK includes the Sentry SDK for crash reporting. As of version 5.39.0, we are using Sentry version 7.22.6. If your project has its own Sentry integration or another one of your project's dependencies has a Sentry integration, you may encounter odd errors.
Your Sentry integration seems to have broken after integrating Incode's Omni SDK
Java-based crash reporting tools rely heavily on the ordering of Thread.UncaughtExceptionHandlers to function correctly. Occasionally issues will occur where crashes aren't passed down the chain of Thread.UncaughtExceptionHandlers.
If this affects you, consider swapping the order in which your own Sentry integration is initialized and IncodeWelcome.Builder()...build() is called. If there's still issues, consider disabling Incode Omni SDK's crash reporting as described later in this document.
Fatal error during SentryAndroid.init(...) at Runtime
The following crash can occur with projects using Sentry 6.x.x:
java.lang.RuntimeException: Unable to get provider io.sentry.android.core.SentryInitProvider: java.lang.RuntimeException: Failed to initialize Sentry's SDK
...
Caused by: java.lang.RuntimeException: Failed to initialize Sentry's SDK
...
Caused by: java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.NoSuchMethodError: No virtual method setEnableScopeSync(Z)V...
If you are affected by this error, you will need to upgrade to version 5.25.0 or newer, and apply the following workaround:
- Exclude the Sentry library from Incode SDK:
implementation ('com.incode.sdk:welcome:5.25.0') { // Mandatory dependency
exclude group: 'io.sentry', module: 'sentry' // Use this line if you're on Incode SDK version older than 5.39.0
exclude group: 'io.sentry', module: 'sentry-android' // Use this line if you're on Incode SDK 5.39.0 or newer
}implementation("com.incode.sdk:welcome:5.25.0") { // Mandatory dependency
exclude(group = "io.sentry", module = "sentry") // Use this line if you're on Incode SDK version older than 5.39.0
exclude(group = "io.sentry", module = "sentry-android") // Use this line if you're on Incode SDK 5.39.0 or newer
}- Disable Incode Omni SDK's crash reporting as described later
Fatal Exception: java.lang.NoSuchMethodError: No virtual method getMainThreadChecker() at Compile time
For projects that use Sentry 8.x.x, or have another dependency that uses this major version, the following crash can occur:
Fatal Exception: java.lang.NoSuchMethodError: No virtual method getMainThreadChecker()Lio/sentry/util/thread/IMainThreadChecker; in class Lio/sentry/SentryOptions; or its super classes (declaration of 'io.sentry.SentryOptions' appears in ...)
This occurs because of breaking changes between Sentry 7.x.x and 8.x.x. If you are affected by this issues, there's 2 options to resolve it.
1. Downgrading the Sentry version compiled in to 7.x.x.
If your project is directly responsible for adding Sentry 8 or higher, simply remove the implementation line from your project's dependencies. This will cause the project to fall back to Sentry 7.x.x included with the Incode Omni SDK.
implementation 'io.sentry:sentry-android:8.x.x'implementation("io.sentry:sentry-android:8.x.x")If another dependency in your project is adding Sentry 8 or higher, you can exclude the version of Sentry provided by that dependency like so:
implementation ('other.dependency.including.sentry:8.x.x') {
exclude group: 'io.sentry', module: 'sentry'
}implementation("other.dependency.including.sentry:8.x.x") { // Mandatory dependency
exclude(group = "io.sentry", module = "sentry")
}2. Upgrade Incode Omni SDK and disable crash reporting
Incode Omni SDK 5.39.0 includes work-arounds to the breaking changes between Sentry 7.x.x and 8.x.x. Upgrade to this version or higher to prevent the crash.
As the aforementioned work-arounds solely prevent crashes as opposed to making crash reporting functional, Incode's crash reporting should be disabled when building the SDK instance.
Disable Incode Omni SDK's crash reporting
If an issue is becoming difficult to resolve, you can disable Incode's crash reporting.
IncodeWelcome.Builder()
...
.setCrashReportingEnabled(false)
.build()new IncodeWelcome.Builder()
...
.setCrashReportingEnabled(false)
.build();Updated 3 days ago
Next, check out the Standard Integration guide on getting Incode up and running.
