Android SDK for KYC

    Library for integrating KYC procedures (document and selfie identification), device data collection, and biometric element display in Android applications.

    Requirements

    • Minimum SDK: 21 (Android 5.0)
    • Target SDK: 34 (Android 14)
    • Kotlin: 1.8+
    • Gradle: 7.0+

    Installation

    Via Maven Central

    Add to your module's build.gradle file:

    dependencies {
        implementation("com.covery.sdk:cvr-sdk:x.y.z")
    }
    

    Permissions

    The SDK requires several permissions to function properly. Add these to your AndroidManifest.xml:

    Required Permissions

    Camera & Hardware:

    <uses-feature
        android:name="android.hardware.camera"
        android:required="true" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    

    Network & Connectivity:

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    

    Optional Permissions

    Permissions for fingerprinting:

    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    

    Note: Camera permissions are required for document and selfie capture. Network permissions are needed for data transmission. Other permissions are optional and depend on your specific use case.

    Quick Start

    1. Initialize SDK

    When to initialize: You can initialize the SDK at the most convenient point for your app:

    • Application.onCreate() — app-wide early initialization
    • Activity.onCreate() — when used only in specific activities
    • Fragment.onCreate() / onViewCreated() / onCreateView() — when usage is scoped to a fragment

    Idempotency: It is safe to call init() multiple times. The SDK is idempotent for the same token and updates internal state if the token changes (e.g., user switch). Recommended practice is to initialize once per active token/session.

    Just‑in‑time init: You may call init() right before first use of any SDK feature (e.g., before prepareKYCProcedure, showKYC, or sendDeviceData). Ensure init() completes before invoking other SDK methods.

    val token = "Bearer your_token_here"
    
    SDKCovery.init(
        context = applicationContext, // Use Context instead of Activity
        token = token,
    ) { sdkEvent ->
        Log.d("SDK", "Event: $sdkEvent")
    }
    

    Note: You can use either Context or Activity for initialization. Using Context is more flexible but requires the SDK to handle Activity launching internally.

    2. Prepare KYC Flow

    Purpose: This method checks if the SDK is ready to perform KYC operations:

    • Validates token and configuration
    • Loads required ML models
    • Initializes camera and hardware components
    • Returns true if ready, false if there are issues

    Option A: Synchronous (Coroutine-based):

    val isPrepared = SDKCovery.prepareKYCProcedure(
        steps = listOf(KYCStepType.DOCUMENT, KYCStepType.SELFIE)
    )
    
    if (!isPrepared) {
        // Handle preparation failure
        Log.e("SDK", "KYC preparation failed")
        // Check SDK events for specific error details
        return
    }
    

    Option B: Asynchronous (Callback-based): For projects that don’t use Kotlin coroutines, the SDK also provides a callback-based wrapper:

    SDKCovery.prepareKYCProcedureAsync(
        steps = listOf(KYCStepType.DOCUMENT, KYCStepType.SELFIE)
    ) { isPrepared ->
        if (!isPrepared) {
            Log.e("SDK", "KYC preparation failed")
            // Check SDK events for specific error details
            return@prepareKYCProcedureAsync
        }
    
        // Continue with KYC flow
    }
    

    3. Start KYC Flow

    Important: The SDK manages all UI logic internally using its own Activity. No need to handle fragments, FragmentManager, or custom UI components. Return the instance of activity.

    Option A: Synchronous (Coroutine-based)

    SDKCovery.showKYC(
        context = applicationContext, // Pass Application context
        flow = CoveryFlowType.FULL,
        validationsSettings = ValidationsSettings.createDefaultDocumentSettings(),
        eventDelay = 1000,
        borderDelay = 1000
    ) { event ->
        Log.d("SDK", "KYC Event: $event")
    }
    

    Option B: Asynchronous (Callback-based) For apps that don’t use coroutines, you can use the async wrapper:

    SDKCovery.showKYCAsync(
        context = applicationContext,
        flow = CoveryFlowType.FULL,
        validationsSettings = ValidationsSettings.createDefaultDocumentSettings(),
        eventDelay = 1000,
        borderDelay = 1000,
        flowEvent = { event -> }
    ) { activity -> }
    

    Note: The SDK automatically adds the FLAG_ACTIVITY_NEW_TASK flag to properly launch the Activity from a non-Activity context.

    4. Device Data Collection (Optional)

    Note: This operation is fully managed by the SDK. No need to handle coroutines or async operations in your app.

    Option A: Synchronous (Coroutine-based)

    SDKCovery.sendDeviceData(applicationContext, token).collect {
        when (result) {
            is NetworkResult.Success -> Log.d("SDK", "Device data sent: ${result.data}")
            is NetworkResult.Error -> Log.e("SDK", "Error: ${result.message}")
            is NetworkResult.Loading -> Log.d("SDK", "Sending device data...")
        }
    }
    

    Option B: Asynchronous (Callback-based) If you prefer a callback approach:

    SDKCovery.sendDeviceDataAsync(
        context = applicationContext,
        token = token
    ) { result ->
        when (result) {
            is NetworkResult.Success -> Log.d("SDK", "Device data sent: ${result.data}")
            is NetworkResult.Error -> Log.e("SDK", "Error: ${result.message}")
            is NetworkResult.Loading -> Log.d("SDK", "Sending device data...")
        }
    }
    

    Customization

    The SDK supports extensive customization of themes, colors, icons, fonts, and localization.

    Override Colors

    <!-- app/src/main/res/values/colors.xml -->
    <resources>
        <!-- Selfie oval frame color -->
        <color name="covery_oval_border">#FF6B35</color>
    
        <!-- Button colors -->
        <color name="covery_apply_background_color_button">#FF6B35</color>
        <color name="covery_retake_background_color_button">#00FFFFFF</color>
        <color name="covery_apply_icon_color_button">#FFFFFF</color>
        <color name="covery_retake_icon_color_button">#FF6B35</color>
        <color name="covery_apply_text_color_button">#FFFFFF</color>
        <color name="covery_retake_text_color_button">#FF6B35</color>
        <color name="covery_apply_stroke_color_button">#FF6B35</color>
        <color name="covery_retake_stroke_color_button">#FF6B35</color>
    
        <!-- Icon and background colors -->
        <color name="covery_back_icon_color">#FF6B35</color>
        <color name="covery_loading_overlay_bg_color">#B3000000</color>
        <color name="covery_loading_overlay_color">#FFFFFF</color>
        <!-- and others in default resource file-->
    </resources>
    

    Override Themes

    <!-- app/src/main/res/values/themes.xml -->
    <resources>
        <style name="covery_theme" parent="covery_base_theme_light">
            <item name="colorPrimary">@color/my_brand_primary</item>
            <item name="colorOnPrimary">@color/my_on_primary</item>
            <item name="colorAccent">@color/my_accent</item>
        </style>
    
        <style name="covery_text_theme" parent="covery_theme">
            <item name="android:fontFamily">@font/arial</item>
            <item name="android:textSize">14sp</item>
            <!-- and others in default resource file-->
        </style>
    </resources>
    

    Override Localization

    <!-- app/src/main/res/values-uk/strings.xml -->
    <resources>
        <string name="covery_face_detection_title">Take a face photo</string>
        <string name="covery_face_result_title">Identity verification</string>
        <string name="covery_face_result_accept_button_text">Confirm photo</string>
        <string name="covery_face_result_retake_button_text">Retake photo</string>
        <!-- and others in default resource file-->
    </resources>
    

    Override Icons

    <!-- app/src/main/res/values/themes.xml -->
    <resources>
        <style name="covery_apply_button_theme" parent="Widget.Material3.Button.OutlinedButton.Icon">
            <item name="icon">@drawable/my_apply_icon</item>
        </style>
    
        <style name="covery_retake_button_theme" parent="Widget.Material3.Button.OutlinedButton.Icon">
            <item name="icon">@drawable/my_retake_icon</item>
        </style>
        <!-- and others in default resource file-->
    </resources>
    

    Events

    The SDK provides comprehensive event tracking for monitoring KYC flow progress and user interactions.

    General Events

    • TOKEN_IS_NULL — token not provided or invalid
    • FLOW_IS_COMPLETED — KYC flow completed

    Selfie Events

    • PHOTO_IS_SENT — selfie successfully sent
    • PHOTO_IS_CREATING — selfie creation in progress
    • PHOTO_IS_CREATED — selfie created
    • TOO_DARK_IMAGE — image too dark
    • TOO_BRIGHT_IMAGE — image too bright
    • IMAGE_IS_NOT_SHARPED — image blurred
    • IMAGE_HAVE_HARD_SHADOW — strong shadow on image
    • SELFIE_CLOSED_EYES — eyes closed
    • SELFIE_HEAD_ROTATION — head turned
    • SELFIE_MANY_FACES — multiple faces in frame
    • SELFIE_NO_FACE_FOUND — no face detected
    • SELFIE_FACE_IS_TOO_FAR — face too far
    • SELFIE_FACE_IS_TOO_CLOSE — face too close
    • SELFIE_DONT_MOVE — user not moving
    • SELFIE_DEVICE_ORIENTATION — incorrect device orientation
    • SELFIE_FACE_IS_NOT_CENTERED — face not centered

    Document Events

    • DOCUMENT_ABSENT — document not detected
    • DOCUMENT_IS_NOT_CENTERED — document not centered
    • EVENT_DOCUMENT_DEVICE_ORIENTATION — incorrect device orientation
    • EVENT_TOO_DARK_IMAGE — image too dark
    • EVENT_TOO_BRIGHT_IMAGE — image too bright
    • EVENT_DOCUMENT_NOT_FOUND — document not found
    • EVENT_IMAGE_IS_NOT_SHARP — image blurred
    • EVENT_DOCUMENT_HARD_SHADOW — strong shadow
    • EVENT_DOCUMENT_ROTATION — document rotation
    • EVENT_DOCUMENT_IS_TOO_FAR — document too far
    • EVENT_DOCUMENT_IS_TOO_CLOSE — document too close
    • EVENT_DOCUMENT_NOT_EXPECTED — unexpected document type
    • EVENT_DOCUMENT_DONT_MOVE — document not moving

    Additional Features

    Touch Tracking (Optional)

    Capture user interactions for behavioral analysis:

    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        SDKCovery.getTouchEvent(event)
        return super.dispatchTouchEvent(event)
    }
    

    Fingerprint View (Optional)

    Send the generated fingerprint to Covery. The lambda provides the main activity instance used by the SDK:

    SDKCovery.showCoveryFingerprint(
        context = applicationContext // Pass Context
    ) { activity ->
        Log.d("SDK", "main activity of fragment: $activity")
    }
    

    Finish and Cleanup

    Purpose: Clear session data and free resources after SDK usage.

    When to use:

    • When the user logs out of your application
    • Before closing the app completely
    • When switching between different user sessions
    • To free up memory and storage resources

    What it does:

    • Finish inner activity
    • Clears cached images and temporary files
    • Resets SDK internal state
    • Releases camera and hardware resources
    • Clears user session data
    // Call when you're done with the SDK
    SDKCovery.clearData()
    

    Important: Always call clearData() when you're finished using the SDK to prevent memory leaks and ensure proper resource cleanup.

    Important Notes

    Resource Naming

    • All SDK resources have the covery prefix (e.g., covery_button_background, covery_text_title)
    • This prevents naming conflicts with your app's resources
    • Never override SDK resources without the proper prefix

    Threading & Coroutines

    • The showKYC() method must be called from the main thread (Dispatchers.Main)
    • All coroutines and async operations are managed internally by the SDK
    • Your app doesn't need to handle coroutines or async logic

    Architecture

    • The SDK uses its own Activity for all UI operations - no fragments, FragmentManager, or custom UI components needed
    • Context-based initialization - use Context instead of Activity for better encapsulation
    • Fully self-contained - the SDK manages all its own lifecycle and resources
    • No external Activity dependencies - the SDK launches its own Activity internally

    ProGuard/R8

    No additional ProGuard rules are required. Consumer rules are automatically applied from the AAR.

    Theme Support

    The SDK supports both light and dark themes and automatically adapts to your app's theme configuration.

    License

    This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

    iOS SDK for KYC

    Swift Platforms CocoaPods Compatible Swift Package Manager

    Requirements

    • macOS (minimum version 15.1.1) [link]
    • Xcode (minimum version 16.1) [link]
    • Ruby (minumum version 2.6.10p210) [link]
    • CocoaPods (minimum version 1.15.2) [link]
    • Shell zsh x86_64-apple-darwin24.0 (minimum version 5.9, it is a default shell for recent versions of macOS)
    • iOS (minimum deployment target 15.5)

    Installation

    There are two approaches how to add CoverySDK to a project: Cocoapods or SPM.

    Cocoapods package manager

    First of all, set up Cocoapods for you project if it hasn't been set up before. [link]

    Add to Podfile this lines of code:

    pod 'CoverySDK', :tag => '1.0.0', :git => 'https://github.com/coverydevteam/ios-sdk.git'
    pod 'TensorFlowLiteSwift'
    

    In a terminal, go to the root of the project where is located Podfile and run the command:

    Swift Package Manager zsh pod install

    Swift Package Manager

    Also there is an option to install CoverySDK via SPM, but you should keep in mind that the dependency TensorFlowLiteSwift currently can be installed only via Cocoapods:

    dependencies: [
        .package(url: "https://github.com/coverydevteam/ios-sdk.git", .upToNextMajor(from: "1.0.0"))
    ]
    

    Preparation

    Before starting using SDK, an app should request a permission to a camera access. App's Info.plist should contain a key NSCameraUsageDescription. Otherwise SDK should work inproperly. This means that the app should ask the permission before and only after that should start showing screens from SDK.

    For example:

    <key>NSCameraUsageDescription</key>
    <string>Required for document and face capture</string>
    

    Note: All methods below may return their callbacks in non-main thread.

    Customization

    When an app launches, SDK should be configured at first time:

    do {
      try SDKCovery.configure(config: nil)
    } catch {
      debugPrint(error.localizedDescription)
    }
    

    There is information about a configuration object:

    /// A configuration object which can be used for SDK initialization
    final public class SDKConfiguration {
    
        /// Positioning of Accept / Retake buttons
        ///  - horizontal:
        ///     * [ Accept ] [ Retake ]
        ///  - vertical:
        ///     * [ Accept ]
        ///     * [ Retake ]
        public enum ButtonsBarAxis : String, Codable {
    
            case horizontal
    
            case vertical
        }
    
        /// Configuration object for text
        public struct TextConfigurationItem : Codable {
    
            /// Initializes a configuration object
            /// - Parameters:
            ///   - fontName: Custom font name. The given font should be exist in the app. If font name isn't set then default one will be used
            ///   - fontSize: Custom font size. If font size isn't set then default one will be used
            public init(fontName: String? = nil, fontSize: CGFloat? = nil)
        }
    
        /// Configuration object for button
        public struct ButtonConfigurationItem : Codable {
    
            public enum ButtonType : String, Codable {
    
                case flat
    
                case bordered
            }
    
            /// Initializes a configuration object
            /// - Parameters:
            ///   - showsIcon: A flag for showing/hiding a button icon. If it is `nil` then default value will be used
            ///   - buttonType: Defines a view of a button. if it is `nil` then default value will be used
            ///   - buttonBorderCornerRadius: A button corner radius in points. If it is `nil` then default value will be used
            ///   - borderWidth: A border width in points. If it is `nil` then default value will be used
            public init(showsIcon: Bool? = nil, buttonType: CoverySDK.SDKConfiguration.ButtonConfigurationItem.ButtonType? = nil, buttonBorderCornerRadius: CGFloat? = nil, borderWidth: CGFloat? = nil)
        }
    
        /// Configuration object for button's bar
        public struct ButtonsBarConfiguration : Codable {
    
            public enum ButtonOrder : String, Codable {
    
                case accept
    
                case retake
            }
    
            /// Initializes a configuration object
            /// - Parameters:
            ///   - layoutAxis: Positioning of Accept / Retake buttons
            ///   - buttonOrder: An order of buttons (Accept | Retake or Retake | Accept)
            ///   - retakeButton: A cuztomization of Retake button
            ///   - acceptButton: A customization of Accept button
            ///   - titleFont: A customization of title font
            ///   - bodyFont: A customization of body font
            public init(layoutAxis: CoverySDK.SDKConfiguration.ButtonsBarAxis? = nil, buttonOrder: CoverySDK.SDKConfiguration.ButtonsBarConfiguration.ButtonOrder? = nil, retakeButton: CoverySDK.SDKConfiguration.ButtonConfigurationItem? = nil, acceptButton: CoverySDK.SDKConfiguration.ButtonConfigurationItem? = nil, titleFont: CoverySDK.SDKConfiguration.TextConfigurationItem? = nil, bodyFont: CoverySDK.SDKConfiguration.TextConfigurationItem? = nil)
        }
    
        /// Initializes button's bar configurations
        /// - Parameters:
        ///   - buttonBarConfiguration: Object for button's bar
        ///   - localizationTableName: Name of custom localization file
        public init(buttonBarConfiguration: CoverySDK.SDKConfiguration.ButtonsBarConfiguration? = nil, localizationTableName: String? = nil)
    }
    

    Sample of localization file for SDK is in Localizable_sample.xcstrings. If you need to add your own localizations, you shold create .strings or .xcstrings file(s) and pass the name of it to SDK during initialization. Current version SDK supports only English localization. In case of altering localization, own variant of English version should be also provided.

    In order to customize a theme of SDK's screens you should create a specific folder structure in your image assets:

    • covery_sdk
      • selfie
        • colors
          • accept_background
          • accept_button_background
          • accept_button_border
          • accept_button_icon
          • accept_button_text
          • accept_text
          • back_button
          • oval_border_selected
          • retake_button_background
          • retake_button_border
          • retake_button_icon
          • retake_button_text
          • scanner_text
        • icons
          • accept_button
          • retake_button

    ACS

    Please don't forget to set a checkmark for a namespace to every folder, otherwise the colours couldn't be get properly by SDK.

    AN

    Finally, you can alter the default SDK fonts with custom ones. They should be properly installed into the app bundle in order to be used by SDK with custom names.

    Initialization

    After obtaining an access token from Covery web-service, SDK should be initialized:

    DKCovery.Authorization.updateToken(<access token from backend>) { error in
        debugPrint("Error: \(error?.localizedDescription)")
    } 
    

    Usage of SDK

    Selfie KYC

    After initializing SDK with access token, there is method to initiate selfie KYC procedure:

    SDKCovery.KYC.startKYCSelfie { error in
        debugPrint("Error: \(error?.localizedDescription)")
    }
    

    Showing KYC scanner UI

    When the previous method completes without any error, the next step is showing a screen of KYC scanner.

    SDKCovery.UIController.showKYC(
        parentController: <parent controller>) {
            // User cancel completion
        }
        serverCompletion: { (result, error) in
            ...
        } cameraCompletion: { error in
            debugPrint("Error: \(error.localizedDescription)")
        }
    

    Alternative method for using in SwiftUI is:

    struct CustomView: View {
        @State private var showsCamera: Bool = false
    
        var body: some View {
            ZStack {
                ...
                someSwiftUIView.showCoveryKYC(
                    showingController: $showsCamera,
                    cancelCompletion: {
                        ...
                    },
                    serverCompletion: { result in
                        debugPrint(result)
                        switch result {
                        case .success(let success):
                            ...
                        case .failure(let error):
                            debugPrint("Camera error: \(error.localizedDescription)")
                        }
                    },
                    cameraCompletion: { error in
                        debugPrint("Camera error: \(error.localizedDescription)")
                    })
            }
        }
    }
    

    After finishing procedure of selfie KYC, a screen, provided by SDK is closed automatically. The response should be returned to either completion serverCompletion or completion cameraCompletion.

    Document KYC

    Document KYC procedure is a slightly longer. Firstly, an app should obtain a list of available documents:

    SDKCovery.KYC.fetchDocumentList { result in
        switch result {
        case .success(let documents):
            ...
        case .failure(let error):
            debugPrint("Camera error: \(error.localizedDescription)")
        }
    }
    

    Note: SDK doesn't provide any UI to represent list of documents, so it is a responsibility of an app. After choosing a specific document type and document name by user, there is a method of initiation document KYC procedure:

    let documentId   = ... // Choosed by user
    let documentType = ... // Choosed by user
    // Name (probably localized version) of choosed document by user. Provided by an app. 
    // Can be **nil**. If this field isn't set, the default name of the document will be applied.
    let documentName = ... 
    SDKCovery.KYC.startKYCDocument(
            documentId: documentId, documentType: documentType, documentName: documentName
        ) { error in
            ...
    }
    

    Finally, an app performs method of showing KYC scanner.

    Device Data

    There is one more method in SDK. It is used for sending a device data to the backend:

    SDKCovery.DataCollection.sendDeviceData { result in
        ...
    }
    

    SDK error list

    Also SDK provides list of predefined errors:

    public enum SDKError: Error {
        /// Informs that the SDK has been used before initialization
        case isntInitialized
        /// A user hasn't allowed yet or has forbidden a camera permission
        case cameraPermission
        /// There is happened a video session creation error
        case videoSessionCreation
        /// There is no enough free space on the device
        case notEnoughDiskSpace
        /// Covery access token is expired
        case authorizationError
        /// Incorrect response from Covery service
        case incorrectResponse
        /// A given document id isn't found or incorrect
        case incorrectDocumentId
        /// Some internal SDK error occurs
        case internalSDKError
        /// Some network error occurs (e. g. backend error)
        case networkError
        /// An error which is caused by an Internet connection issue
        case internetConnectionError
    }