Skip to content

About

No description, website, or topics provided.

Resources

Contributing

Stars

2 stars

Watchers

2 watching

Forks

Latest commit

 

History

109 Commits

Folders and files

Repository files navigation

DiditSDK for Android

A lightweight Android SDK for identity verification. Server-driven, minimal configuration required.

Requirements

  • Android API level 23+ (Android 6.0 Marshmallow and above)
  • Kotlin 1.9+
  • Jetpack Compose (included as a transitive dependency)

Feature Availability by API Level

Feature API 23 API 24+
Document auto-detection (ML) No (falls back to manual capture) Yes
Face auto-detection (ML) No (falls back to manual capture) Yes
Camera permissions Runtime Runtime

Note: The SDK gracefully degrades on older devices. ML-based document and face auto-detection require API 24+ (MediaPipe) and fall back to manual capture with a timed button on API 23. All other features work across the full supported range.

Permissions

The SDK requires the following permissions. These are declared in the SDK's AndroidManifest.xml and will be merged automatically into your app's manifest:

Permission Description
INTERNET Network access for API communication
ACCESS_NETWORK_STATE Detect network availability
CAMERA Document scanning and face verification
NFC Read NFC chips in passports/ID cards

Camera and NFC Features

The SDK declares android.hardware.camera and android.hardware.nfc as optional features (android:required="false"). This ensures your app can be installed on devices without a camera or NFC hardware — the SDK will gracefully handle missing hardware at runtime.

Installation

Step 1: Add the repository

Add the Didit Maven repository to the repositories block in your settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
    }
}

Or if using settings.gradle (Groovy):

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository" }
    }
}

Step 2: Add the dependency

Add the SDK dependency to your app's build.gradle.kts:

dependencies {
    implementation("me.didit:didit-sdk:4.9.1")
}

Or if using build.gradle (Groovy):

dependencies {
    implementation "me.didit:didit-sdk:4.9.1"
}

Starting with 4.0.0 the SDK ships as separate artifacts (didit-sdk-core, didit-sdk-autodetection, didit-sdk-nfc, didit-sdk, plus the optional didit-sdk-wallet add-on since 4.6.0) so apps only pay the binary cost of features they use. See SDK Variants and App Size for what each variant costs and how to keep the download small.

Step 3: Add packaging exclusion

Add this to your app's android block to avoid build conflicts:

android {
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}

That's it! Gradle will automatically resolve all transitive dependencies.

SDK Variants and App Size

Pick the smallest artifact that covers the features you use:

Artifact Auto-capture NFC What it adds
didit-sdk-core – – UI, camera, manual capture (~5 MB of code before R8)
didit-sdk-autodetection ✓ – MediaPipe runtime for document/face auto-detection
didit-sdk-nfc – ✓ JMRTD passport chip reading
didit-sdk-wallet – – Optional add-on: native WalletConnect wallet-signing (since 4.6.0)
didit-sdk ✓ ✓ Everything above, wallet add-on included
didit-auth – – End-user authentication (DiditAuth), on its own or next to any artifact above

Since 4.6.0, native WalletConnect wallet-signing lives in the optional me.didit:didit-sdk-wallet add-on instead of didit-sdk-core, which drops the Reown/WalletConnect dependencies (several MB of transitive jars) from every build that does not use them. The full me.didit:didit-sdk bundle includes the add-on, so its behavior is unchanged. If you depend on a slimmer artifact and want wallet-ownership signing to run natively in your app, add me.didit:didit-sdk-wallet alongside it; without it the SDK completes wallet ownership through the browser-based flow instead, so the feature keeps working either way.

The ML models used for auto-detection are downloaded at runtime and cached — they are never inside your APK. The install cost of auto-capture is the MediaPipe native runtime, and it is per CPU architecture: ~10.4 MB for arm64-v8a, ~6.9 MB for armeabi-v7a, ~12.6 MB for x86_64, ~13.9 MB for x86.

To keep that from multiplying, follow these rules:

  1. Publish an Android App Bundle (AAB). Google Play then delivers only the device's own architecture (~10 MB installed, roughly 4 MB of compressed download on an arm64 phone) and only the device's language resources. A universal APK instead carries all four architectures — over 40 MB of native libraries — which is the most common cause of "the SDK is huge" measurements.

  2. If you must distribute a single APK and your audience is ARM phones and tablets, restrict architectures in your build.gradle.kts:

    android {
        defaultConfig {
            ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }
        }
    }

    Keep every ABI your users actually run: add x86_64 if you target Chromebooks or other x86 devices, or publish per-ABI APK splits so no device loses support.

  3. Enable R8 — isMinifyEnabled = true and isShrinkResources = true in your release build type (minifyEnabled true / shrinkResources true in Groovy build.gradle). The SDK ships consumer rules, so no extra configuration is needed and unused SDK code is stripped from your build.

  4. Limit bundled languages if you do not ship all 48 SDK locales, e.g. resConfigs("en", "sw") in defaultConfig.

Quick Start

Step 1: Initialize the SDK

Initialize the SDK in your Application.onCreate():

import me.didit.sdk.DiditSdk

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DiditSdk.initialize(this)
    }
}

Step 2: Observe SDK state and launch the UI

import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state to launch UI when ready
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Loading, Idle, CreatingSession */ }
                }
            }
        }
    }

    private fun startVerification() {
        DiditSdk.startVerification(
            token = "your-session-token"
        ) { result ->
            when (result) {
                is VerificationResult.Completed -> {
                    Log.d("Didit", "Session: ${result.session.sessionId}")
                    Log.d("Didit", "Status: ${result.session.status.rawValue}")
                }
                is VerificationResult.Cancelled -> {
                    Log.d("Didit", "User cancelled")
                }
                is VerificationResult.Failed -> {
                    Log.e("Didit", "Failed: ${result.error.message}")
                }
            }
        }
    }
}

Starting verification

There are two ways to start the verification flow:

Option A: With existing session token (from your backend)

// Your backend creates the session and returns a token
DiditSdk.startVerification(
    token = "your-session-token"
) { result ->
    handleResult(result)
}

Option B: With workflow ID (SDK creates session)

// SDK creates the session using your workflow ID
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123"  // Optional: your user identifier
) { result ->
    handleResult(result)
}

Configuration

You can customize the SDK behavior using Configuration:

import me.didit.sdk.Configuration
import me.didit.sdk.core.localization.SupportedLanguage

val configuration = Configuration(
    languageLocale = SupportedLanguage.SPANISH,  // Force Spanish language
    fontFamily = "my_custom_font",                // Custom font (must be in res/font/)
    loggingEnabled = true                         // Enable debug logging
)

DiditSdk.startVerification(
    token = "your-session-token",
    configuration = configuration
) { result ->
    handleResult(result)
}

Configuration Options

Option Type Default Description
languageLocale SupportedLanguage? Device locale Force a specific language
fontFamily String? System font Custom font resource name (from res/font/)
loggingEnabled Boolean false Enable SDK debug logging

Language Settings

The SDK supports 54 languages. If no language is specified, the SDK uses the device locale with English fallback.

// Use device locale (default)
val config = Configuration()

// Force specific language
val config = Configuration(languageLocale = SupportedLanguage.FRENCH)

Supported Languages

Language Value Language Value
Albanian ALBANIAN Kazakh KAZAKH
Arabic ARABIC Korean KOREAN
Armenian ARMENIAN Kyrgyz KYRGYZ
Bengali BENGALI Latvian LATVIAN
Bosnian BOSNIAN Lithuanian LITHUANIAN
Bulgarian BULGARIAN Macedonian MACEDONIAN
Catalan CATALAN Malay MALAY
Chinese CHINESE Mongolian MONGOLIAN
Chinese (Simplified) CHINESE_SIMPLIFIED Montenegrin MONTENEGRIN
Chinese (Traditional) CHINESE_TRADITIONAL Norwegian NORWEGIAN
Croatian CROATIAN Persian PERSIAN
Czech CZECH Polish POLISH
Danish DANISH Portuguese PORTUGUESE
Dutch DUTCH Portuguese (Brazil) PORTUGUESE_BRAZIL
English ENGLISH Romanian ROMANIAN
Estonian ESTONIAN Russian RUSSIAN
Finnish FINNISH Serbian SERBIAN
French FRENCH Slovak SLOVAK
Georgian GEORGIAN Slovenian SLOVENIAN
German GERMAN Somali SOMALI
Greek GREEK Spanish SPANISH
Hebrew HEBREW Swedish SWEDISH
Hindi HINDI Thai THAI
Hungarian HUNGARIAN Turkish TURKISH
Indonesian INDONESIAN Ukrainian UKRAINIAN
Italian ITALIAN Uzbek UZBEK
Japanese JAPANESE Vietnamese VIETNAMESE

Advanced Options

Contact Details (Prefill)

Provide contact details to prefill verification forms and enable notifications:

import me.didit.sdk.models.ContactDetails

val contactDetails = ContactDetails(
    email = "user@example.com",
    sendNotificationEmails = true,  // Send status update emails
    emailLang = "en",               // Email language
    phone = "+14155552671"          // E.164 format
)

DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    contactDetails = contactDetails
) { result ->
    handleResult(result)
}

Expected Details (Cross-Validation)

Provide expected user details for cross-validation with extracted data:

import me.didit.sdk.models.ExpectedDetails

val expectedDetails = ExpectedDetails(
    firstName = "John",
    lastName = "Doe",
    dateOfBirth = "1990-05-15",   // YYYY-MM-DD format
    nationality = "USA",          // ISO 3166-1 alpha-3
    country = "USA"
)

DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    expectedDetails = expectedDetails
) { result ->
    handleResult(result)
}

Metadata

Store custom JSON metadata with the session (not displayed to user):

DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123",
    metadata = "{\"internalId\": \"abc123\", \"source\": \"mobile\"}"
) { result ->
    handleResult(result)
}

Verification Results

The VerificationResult sealed class provides the outcome of the verification:

Result Cases

Case Description
Completed(session) Verification flow completed (approved, pending, or declined)
Cancelled(session) User cancelled the verification flow
Failed(error, session) An error occurred during verification

SessionData

Each result includes a SessionData object:

Property Type Description
sessionId String The unique session identifier
status VerificationStatus Status: APPROVED, PENDING, DECLINED

VerificationError

Error Description
SessionExpired The session has expired
NetworkError Network connectivity issue
CameraAccessDenied Camera permission not granted
NotInitialized SDK not initialized
Unknown(message) Other error with message

Example Usage

DiditSdk.startVerification(token = "your-token") { result ->
    when (result) {
        is VerificationResult.Completed -> {
            when (result.session.status) {
                VerificationStatus.APPROVED -> println("Approved!")
                VerificationStatus.PENDING -> println("Under review")
                VerificationStatus.DECLINED -> println("Declined")
            }
        }
        is VerificationResult.Cancelled -> {
            println("Cancelled: ${result.session?.sessionId ?: "unknown"}")
        }
        is VerificationResult.Failed -> {
            println("Error: ${result.error.message}")
        }
    }
}

ProGuard / R8

The SDK includes its own consumer ProGuard rules. No additional configuration is needed.

If you use R8 full mode, you may need to add this to your gradle.properties:

android.enableR8.fullMode=false

License

Copyright (c) 2026 Didit. All rights reserved.

About

No description, website, or topics provided.

Resources

Contributing

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages