Android SDK guide

Requirements and prerequisites

Requirements

  • Veriff Android SDK needs your minSdkVersion to be of 26 or above

  • Kotlin 1.7.21 or above

  • Supports android-gradle-plugin version 7.2.0 and above

  • The SDK is using AndroidX support libraries

List of all direct transitive dependencies

  • androidx.annotation:annotation-experimental:1.1.0

  • androidx.annotation:annotation:1.7.1

  • androidx.appcompat:appcompat:1.6.1

  • androidx.concurrent:concurrent-futures:1.1.0

  • androidx.constraintlayout:constraintlayout:2.1.4

  • androidx.core:core-ktx:1.9.0

  • androidx.core:core:1.9.0

  • androidx.databinding:viewbinding:8.6.1

  • androidx.exifinterface:exifinterface:1.3.7

  • androidx.fragment:fragment-ktx:1.5.7

  • androidx.lifecycle:lifecycle-common:2.5.1

  • androidx.lifecycle:lifecycle-livedata:2.5.1

  • androidx.lifecycle:lifecycle-runtime-ktx:2.5.1

  • androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1

  • androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01

  • com.google.android.gms:play-services-mlkit-face-detection:17.1.0

  • com.google.android.material:material:1.4.0

  • com.google.auto.value:auto-value-annotations:1.7

  • com.google.dagger:dagger:2.45

  • com.google.guava:listenablefuture:1.0

  • com.squareup.okhttp3:logging-interceptor:4.10.0

  • com.squareup.okhttp3:okhttp:4.10.0

  • com.squareup.okio:okio-jvm:3.2.0

  • com.squareup.okio:okio:3.2.0

  • org.bouncycastle:bcprov-jdk18on:1.76

  • org.bouncycastle:bcutil-jdk18on:1.76

  • org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.21

  • org.jetbrains.kotlin:kotlin-stdlib:1.7.21

  • org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4

  • org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4

Prerequisites

  • You have an active account with Veriff (see the Getting Started section)

  • You have an integration with Veriff (see the Getting Started section)

  • You have set up webhook(s) to get replies from Veriff (see the Webhooks section)


Add Android SDK to the project

Step 1: Add a new Maven destination

Open the root build.gradle file and add a new Maven destination to the repositories in the allprojects section:

allprojects {
    repositories {
        maven { url = uri("https://cdn.veriff.me/android/") }
        google()
        mavenCentral()
    }
}
allprojects {
   repositories {
       maven { url "https://cdn.veriff.me/android/" }
       google()
       mavenCentral()
   }
}

Alternatively, when using Gradle 7+, add the Maven repository to your settings.gradle file:

dependencyResolutionManagement {
    repositories {
        maven { url = uri("https://cdn.veriff.me/android/") }
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositories {
        maven { url "https://cdn.veriff.me/android/" }
        google()
        mavenCentral()
    }
}

Step 2: Add the Veriff SDK dependency

Add to the application build.gradle file:

implementation("com.veriff:veriff-library:$latestVeriffAndroidSdkVersion")
implementation 'com.veriff:veriff-library:$latestVeriffAndroidSdkVersion'


Add permissions

Camera and audio recording permissions

The SDK will request all the permissions it needs.

If you are explicitly removing permissions, make sure that the CAMERA, RECORD_AUDIO permissions are not removed using tools:node="remove" in your app’s manifest file. Ignore this if you are not explicitly removing any permissions.

Foreground service information declaration in Play Console 

The SDK declares and uses the FOREGROUND_SERVICE_DATA_SYNC

If you distribute your application on Google Play, then you must declare the foreground service information in Play Console (Policy > App content > Foreground service Permissions) . Read the instructions in the Google Play[↗]. 

According to Google, you need to:

  1. Provide a description of the app functionality that is using each foreground service type.
    1. You may use the following description: “The Veriff SDK uses the foreground service to upload end-user data to Veriff's servers for verification purposes.” 
  2. Describe the user impact if the task is deferred by the system (does not start immediately), and/or the task is interrupted by the system (paused and/or restarted).
    1. You may use the following description: “If the task is deferred or interrupted by the system, the end-user verification will be delayed.” 
  3. Include a link to a video demonstrating each foreground service feature. The video should demonstrate the steps the user needs to take in your app in order to trigger the feature. 
    1. Please record a video of your app's Veriff SDK integration and share it (via link, Youtube, etc.)
  4. Choose your specific use case for each foreground service type
    1. Select use case: "Network transfer: Upload or download / Other"

See also Veriff's note on data collection purposes in your app [↗].

Note that all the info above is only for Google for review purposes, it is not accessible to the end-users.


Start the verification flow

The verification flow must be launched from the activity class with a unique session (= sessionURL).

import com.veriff.Sdk

val intent = Sdk.createLaunchIntent(activity, sessionUrl)
startActivityForResult(intent, REQUEST_CODE)
import com.veriff.Sdk;

Intent intent = Sdk.createLaunchIntent(activity, sessionUrl);
startActivityForResult(intent, REQUEST_CODE);

Parameter

Description

REQUEST_CODE*

An constant integer that is defined in your activity and identifies the request. It helps differentiate this request from others when the result is returned in the onActivityResult.

A constant integer that identifies the request. It helps differentiate this request from others when the result is returned in the onActivityResult callback

sessionUrl*

A combination of the base URL and the sessionToken, created as soon as a verification session is created. You can find its value in the response payload of your POST /sessions[↗] call, as verification.url. See Create a verification session article for more info.

* Required parameter

A session is valid for 7 days and expires automatically after that.

What happens after the end-user leaves the flow?

When the end-user leaves the verification flow, i.e. a session is canceled or finished, the Veriff SDK is closed. The end-user is taken back to your application. The end-user flow completion status is returned to the host application, see the Get verification session status sub-section below for more info.


Verification session status

When a session is cancelled or finished, the Veriff SDK is closed and the end-user is taken back to your application.

Callbacks about the end-user flow completion status are sent to your mobile application. To capture the status, override the onActivityResult method in your activity that started the verification flow.

This is not the verification session decision.

This indicates whether the end-user was able to complete all the steps in the verification flow or not.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == REQUEST_CODE) {
        val result = Result.fromResultIntent(data)
        result?.let { 
            handleResult(it)
        }
    }
    super.onActivityResult(requestCode, resultCode, data)
}

private fun handleResult(result: Result) {
    when (result.status) {
        Status.DONE -> {
            // The end-user successfully submitted the session, the session is completed from their perspective
        }
        Status.CANCELED -> {
            // The end-user canceled the verification process
        }
        Status.ERROR -> {
            // An error occurred during the flow, Veriff has already shown UI, no need to display
            // a separate error message here
            Log.w(TAG, "Verification error occurred: ${result.error}")
        }
    }
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_CODE) {
        Result result = Result.fromResultIntent(data);
        if (result != null) {
            handleResult(result); //see below for handling the result
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}

public void handleResult(Result result) {
    switch (result.getStatus()) {
    case DONE:
        // The end-user successfully submitted the session, the session is completed from their perspective
        break;
    case CANCELED:
        // The end-user canceled the verification process
        break;
    case ERROR:
        // An error occurred during the flow, Veriff has already shown UI, no need to display
        // a separate error message here
        Log.w(TAG, "Verification error occurred: " + result.getError());
        break;
    }
}


Verification session decision

Veriff returns info about the verification session decision, extracted data, registries checks etc. via webhooks. You need to set up webhooks and tie them to your system.

 See Webhooks Guide > Set up webhooks sub-section for detailed overview of the setup process


Add error logging

To turn on logging, add your logging implementation instance (instance of com.veriff.Logger class) to the SDK before launching the SDK.

Sdk.setLogger(myLoggerImplementation)
val intent = Sdk.createLaunchIntent(activity, sessionUrl)
startActivityForResult(intent, REQUEST_CODE)
Sdk.setLogger(myLoggerImplementation);
Intent intent = Sdk.createLaunchIntent(activity, sessionUrl);
startActivityForResult(intent, REQUEST_CODE);


Customize the SDK

SDK customization is optional

It is possible to customize the look and feel of the UI to match your branding. You can change primitives such as colors and fonts, set the language settings for the SDK, and change if/how an intro screen is displayed.

Match the brand

You can customize the look and feel of the SDK flow by passing a Branding object via Configuration to createLaunchIntent as shown and explained in the example below.

Note: all custom values for branding are optional. If a value is not provided for them, the default Veriff color and logo will be used.

Branding object options

import com.example.mysdk.Branding
import com.example.mysdk.Configuration
import com.example.mysdk.Sdk

// ... other imports

fun launchSdk() {
    val branding = Branding.Builder()
        .logo(R.drawable.logo)
        .background(resources.getColor(R.color.background_color))
        .onBackground(resources.getColor(R.color.on_background_color))
        .onBackgroundSecondary(resources.getColor(R.color.on_background_secondary_color))
        .onBackgroundTertiary(resources.getColor(R.color.on_background_tertiary_color))
        .primary(resources.getColor(R.color.primary_color))
        .onPrimary(resources.getColor(R.color.on_primary_color))
        .secondary(resources.getColor(R.color.secondary_color))
        .onSecondary(resources.getColor(R.color.on_secondary_color))
        .cameraOverlay(resources.getColor(R.color.camera_overlay_color))
        .onCameraOverlay(resources.getColor(R.color.on_camera_overlay_color))
        .outline(resources.getColor(R.color.outline_color))
        .success(resources.getColor(R.color.success_color))
        .error(resources.getColor(R.color.error_color))
        .buttonRadius(48f)
        .build()

    val configuration = Configuration.Builder()
        .branding(branding)
        .build()

    val intent = Sdk.createLaunchIntent(this, sessionUrl, configuration)
    startActivityForResult(intent, REQUEST_CODE)
}
Branding branding = new Branding.Builder()
        .logo(R.drawable.logo)
        // Screen and dialog background color
        .background(getResources().getColor(R.color.background_color))
        // Non-surface content (such as text, icons) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .onBackground(getResources().getColor(R.color.on_background_color))
        // Secondary non-surface content (such as text) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .onBackgroundSecondary(getResources().getColor(R.color.on_background_secondary_color))
        // Tertiary non-surface content (such as text) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .onBackgroundTertiary(getResources().getColor(R.color.on_background_tertiary_color))
        // Primary surfaces (such as buttons) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
        .primary(getResources().getColor(R.color.primary_color))
        // Non-surface content (such as text) displayed on `primary` surfaces.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `primary`
        .onPrimary(getResources().getColor(R.color.on_primary_color))
        // Secondary surfaces (such as bullet points and illustrations) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
        .secondary(getResources().getColor(R.color.secondary_color))
        // Non-surface content (such as text) displayed on `secondary` surfaces.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `secondary`
        .onSecondary(getResources().getColor(R.color.on_secondary_color))
        // Backgroung color of the overlay area on all the screens with camera
        .cameraOverlay(getResources().getColor(R.color.camera_overlay_color))
        // All UI elements on all the screens with camera on top of camera overlay
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `cameraOverlay`
        .onCameraOverlay(getResources().getColor(R.color.on_camera_overlay_color))
        // Color used for various outlines and boundaries of UI elements
        .outline(getResources().getColor(R.color.outline_color))
        // Error indicators (such as text, borders, icons) displayed on `background`
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .success(getResources().getColor(R.color.success_color))
        // Success indicators (such as borders, icons) displayed on `background`
        // Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
        .error(getResources().getColor(R.color.error_color))
        // Button corner radius, in `dp`
        .buttonRadius(48f)
        .build();

Configuration configuration = new Configuration.Builder()
        .branding(branding)
        .build();


Intent intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration);
startActivityForResult(intent, REQUEST_CODE);

→ See the Visual SDK customization guides article for design examples

Font

You can customize the fonts used in the SDK by passing the resource IDs of the fonts you want to use. Make sure that you have added the font files to the font resource folder in your app.

A custom font can be set by passing a com.veriff.Font object to the font method of Branding builder. The com.veriff.Font builder accepts three types of fonts via the setRegular, setMedium and setBold methods.

brandingBuilder.font = com.veriff.Font.Builder()
    .setRegular(R.font.comic_neue_regular)
    .setMedium(R.font.comic_neue_medium)
    .setBold(R.font.comic_neue_bold)
    .build()
brandingBuilder.font(
    new com.veriff.Font.Builder()
        .setRegular(R.font.comic_neue_regular)
        .setMedium(R.font.comic_neue_medium)
        .setBold(R.font.comic_neue_bold)
        .build()
);

Intro screen

It is possible to customise if the end-user flow begins with Veriff intro screen or no intro screen at all.

In some cases, it is possible to skip the Veriff’s generic introduction screen and use your own before Veriff’s SDK is launched.

Check with your Solutions Engineer to confirm if this feature can be enabled for your integration

If it is possible, then:

  • You agree your own introduction screen visuals and copy with our Solutions Engineer and get relevant legal documents signed in case they are needed

  • After that Veriff will enable custom introduction screen from backend for your integrations

  • After you have implemented your own introduction screen you can change the configuration option specified below

val configuration = Configuration.Builder()
    .customIntroScreen(true)
    .build()
Configuration configuration = new Configuration.Builder()
        .customIntroScreen(true)
        .build();

Adding the configuration alone in your app is not enough to enable the custom intro screen. Make sure to contact your solutions engineer so they can enable the feature for your integration.

User interface locale settings

You can set a locale(java.util.Locale) for the SDK from the app itself.

val appLocale = Locale.ENGLISH
val configuration = Configuration.Builder()
    .locale(appLocale)
    .build()

val intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration)
startActivityForResult(intent, REQUEST_CODE)
Locale appLocale = Locale.ENGLISH;
Configuration configuration = new Configuration.Builder()
        .locale(appLocale)
        .build();

Intent intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration);
startActivityForResult(intent, REQUEST_CODE);

→ See Supported languages in SDKs article for more info


Need to exclude ML Kit support?

Veriff Android SDK uses ML Kit[↗] for things like automatic selfie capture and accessibility feedback. It uses on-device models that are pre-downloaded by Play services.

If your app cannot use Play services at all, then you can exclude the transitive mlkit dependency. This will remove any dependencies on ML Kit and disable the use of these ML modules at runtime.

implementation("com.veriff:veriff-library:6.+") {
    exclude(group = "com.veriff", module = "mlkit")
}
implementation('com.veriff:veriff-library:6.+') {
    exclude group: 'com.veriff', module: 'mlkit'
}