Android

This guide will get you started with the Android SDK for onboarding with Incode.

Minimum hardware requirements

Ram: 3GB
Back-facing camera: 5MP Front-facing (selfie) camera: 2MP

Installation

🚧

Important: Support for distribution through Artifactory ended September 19th, 2025. If you are currently using Artifactory in your production integration, you must complete the migration to GitHub Packages to ensure uninterrupted access to the SDK.

The Incode Omni Android SDK is distributed through GitHub Packages. To receive credentials for the SDK, contact your enterprise customer success manager or [email protected].

Add the following Github packages credentials to your project dependencies. For more information about declaring dependencies, read the Gradle documentation.

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 Android SDK is dependent on jitpack, so you must also add the following maven repository.

repositories {
    maven { url "https://jitpack.io" }
}
repositories {
    maven("https://jitpack.io")
}

If add Google and Maven Central are not already in your file, add them.

repositories {
    google()
    mavenCentral()
}
repositories {
    google()
    mavenCentral()
}

The dependencies should look like the following image:

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"
        }
    }
}

Incode requires a minimum of Java 8 in your module-level app/build.gradle. This applies to 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.

Library dependencies

The Incode Omni Android SDK has several library dependencies. Core dependencies are required. Optional dependencies are based on the use case. See the table following the image.

After you've added the dependencies, try building the project. Refer to the troubleshooting section if you have errors. You can begin integration once the project successfully builds.

dependencies {
    ...

    // Incode Omni SDK
    implementation 'com.incode.sdk:welcome:5.42.0' // Required core dependency
    implementation 'com.incode.sdk:core-light:3.0.6' // 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.1' // 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.42.0") // Required core dependency
    implementation("com.incode.sdk:core-light:3.0.6") // 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.1") // 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
}
DependencyTypeDescription
welcomeCore (required)Main module; contains all core SDK functionality
core-lightCore (required)Contains image processing libraries used in the SDK
cameraOptional (based on use case)Add when using the SelfieScan module on the -nu line of releases
extensionsOptional (based on use case)Add when using custom Theme Configuration , Dynamic Localization , or Runtime Localization
nfcOptional (based on use case)Required when using the NfcScan SDK module. Additional configuration is also required.
video-streamingOptional (based on use case)Add when using the Conference module or the streamFrames feature in the IdScan or SelfieScan modules
model-face-recognitionOptional (based on use case)Required when using the local device face recognition feature. This feature is only available for Face Login
model-id-face-detectionOptional (based on use case)Add when using checks to detect the front and back sides of the user ID
model-liveness-detectionOptional (based on use case)Required when using the local device liveness detection feature

Required permissions

The Incode Android SDK manifest files declare the permissions shown in the following images.

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 use the screen recording features of the IdScan, SelfieScan, or VideoSelfie modules, you can safely exclude foreground service permissions. To do so, add a block in your application as shown in the following image.

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 if additional permissions are given. However, using these permissions will subject your app to additional scrutiny when publishing on Google Play. You should only grant these permissions if your app has an existing use case for them.

Querying all apps on the device on Android 11+

When the SDK performs root detection, it can take more actions to find evidence of a rooted device if you add the following permission:

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

On Android 11+, the default is for the root detection algorithm to 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, actions that required the QUERY_ALL_PACKAGES permission on Android 11+ are taken by default 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" />

On Android 12+, the second highest sample rate available is used by default when determining the device's motionStatus. Below Android 12, using the highest sampling rate is automatic.

Troubleshooting

This section provides examples of build errors and messages, explains their meaning if the message is unclear, and offers potential solutions.

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.

What it means

You have set allowBackup in your AndroidManifest.xml to true, but the Welcome SDK has this value set to false.

How to solve it

Having allowBackup set to true is a potential security issue. We recommend setting it to false.

If you are sure you want to allow backups, add tools:replace="android:allowBackup" to the <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
}}

How to solve it

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.

How to solve it

In your module-level app/build.gradle, add the following ndk abi filters to 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)

What it means

This crash occurs when the okhttp3:okhttp dependency version is different from okhttp3:logging-interceptor or okhttp3:okhttp-urlconnection dependencies and trying to init Incode SDKs.

For example, the dependencies in the following list are not all of the same version. These dependencies in the Project's External Libraries will cause version inconsistency and result in this crash:

  • okhttp3:logging-interceptor:3.4.1
  • okhttp3:okhttp-urlconnection:3.4.1
  • okhttp3:okhttp:4.5.0

How to solve it

For the preceding example, set the version of okhttp3:logging-interceptor & okhttp3:okhttp-urlconnection to 4.5.0.

To override the existing lower versions, add the following implementations inside build.gradle:

dependencies {
    ...

    implementation 'com.squareup.okhttp3:logging-interceptor:4.5.0'
    implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.5.0'
}

The crash will still occur if you only have either the logging-interceptor or okhttp-urlconnection dependency as shown in the following examples.

Crashes if you have in External Libraries these dependencies:

  • okhttp3:logging-interceptor:3.4.1
  • okhttp3:okhttp:4.5.0

Crashes as well if you have in External Libraries these dependencies:

  • okhttp3:okhttp-urlconnection:3.4.1
  • okhttp3: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'

What it means

For projects using Gradle 6.8 or higher, a new way of defining dependencies in settings.gradle with the dependencyResolutionManagement block was introduced.

How to solve it

Move the maven repo declaration from the project build.gradle to the location shown in the following image. For additional information, see this page at 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

What it means

Your build was configured to prefer settings repositories over project repositories but the repository Google was added by the build file build.gradle.

How to solve it

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

Beginning with version 5.24.0, the Incode SDK has included the Sentry SDK for crash reporting. As of version 5.39.0, the SDK uses 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 appears broken after integrating the Incode Omni SDK

Java-based crash reporting tools rely heavily on the ordering of Thread.UncaughtExceptionHandlers to function correctly. Occasionally, issues 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 are still issues, consider disabling the Incode Omni SDK 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, upgrade to Incode SDK version 5.25.0 or newer and apply the following workaround:

  1. Exclude the Sentry library from Incode SDK as shown in the following image:
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
}
  1. Disable Incode Omni SDK 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 crash shown in the following image 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 issue, you have two options to resolve it.

Option One: Downgrade the Sentry version 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. The project will 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 as shown in the following image:

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")
}

Option Two: 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.

These workarounds solely prevent crashes as opposed to making crash reporting functional. Therefore, you should disable Incode's crash reporting when building the SDK instance.

Disable Incode Omni SDK crash reporting

If an issue is becoming difficult to resolve, you can disable SDK crash reporting.

IncodeWelcome.Builder()
    ...
    .setCrashReportingEnabled(false)
    .build()
new IncodeWelcome.Builder()
    ...
    .setCrashReportingEnabled(false)
    .build();

What’s Next

Next, check out the Standard Integration guide on getting Incode up and running.