iOS (Compat) Liveness SDK

Our iOS SDK enables seamless integration of real-time liveness detection into your mobile applications. To get started with our SDK, follow the guide below:

Get your Public Merchant Key

Youverify Liveness SDK Compat is the compatibility version of the iOS SDK, designed for integrating active liveness detection into UIKit-based applications. This SDK is tailored for apps that need to support iOS 12 and later, providing a reliable solution for older iOS versions.

Features

  • Active Liveness Detection: Requires users to perform specific actions (e.g., head movements, answering questions) to confirm liveness. Available on iOS 12+.

  • Built with UIKit, ensuring compatibility with legacy iOS applications.

Note: Passive liveness detection is not supported in this version.

Installation

Step 1: Add to Podfile

Add the following to your Podfile:

pod 'YouverifyLivenessSDKCompat'
pod 'MediaPipeTaskVision'

Step 2: Install Dependencies

Run this command in your terminal:

pod install

Step 3: Open Workspace

Open the generated .xcworkspace file in Xcode.

Project Configuration

To avoid linker errors:

  1. Open your project in Xcode.

  2. Go to Project > Pods.

  3. Under Other Linker Flags (OTHER_LDFLAGS) for both .debug and .release, ensure the following are not present:

    • force-load

    • -framework mediaPipetaskvision

    • -framework mediataskCommon


Usage

1. Import the SDK

In your Swift file:

import YouverifyLivenessSDK

2. Initialize the SDK

Create an instance of YVLiveness with your configuration:

private var yvLiveness = YVLiveness(
    publicKey: Environment.shared.value(forKey: "API_KEY") ?? "",
    user: YVLivenessUser(firstName: "Ugochukwu"),
    onSuccess: { data in
        print("The success data is \(data)")
    },
    onFailure: { errorData in
        print("The error data is \(errorData)")
    },
    sandboxEnvironment: false
)
  • The publicKey is dynamically retrieved from an environment variable (Environment.shared.value(forKey: "API_KEY") ?? "") in the working code. Replace this with your actual API key or retrieval logic.

  • The user parameter requires a firstName, while optional fields like lastName and email can be added if needed (see Configuration Options).

3. Start Liveness Detection

Launch the SDK with a list of tasks:

yvLiveness.startSDK(tasks: tasks)
DispatchQueue.main.async {
    self.addLivenessViewController()
}

4. Manage the Liveness View Controller

Add these methods to handle the liveness UI:

private var livenessViewController: YVLivenessViewController?

private func addLivenessViewController() {
    guard livenessViewController == nil else { return }
    let vc = YVLivenessViewController(sdk: yvLiveness)
    vc.delegate = self
    addChild(vc)
    view.addSubview(vc.view)
    vc.didMove(toParent: self)
    livenessViewController = vc
}

private func removeLivenessViewController() {
    guard let vc = livenessViewController else { return }
    vc.willMove(toParent: nil)
    vc.view.removeFromSuperview()
    vc.removeFromParent()
    livenessViewController = nil
}
  • The guard statement in addLivenessViewController() prevents duplicate additions of the view controller.

5. Handle Modal Closing

Implement the delegate to close the liveness UI:

extension MainViewController: YVLivenessViewDelegate {
    func closeModal() {
        DispatchQueue.main.async {
            self.removeLivenessViewController()
        }
    }
}

Configuration Options

Option
Type
Required
Description
Default
Possible Values

publicKey

String

Yes

Your API key for authentication

-

Any string

user

Class

Yes

User details (requires firstName)

-

See below

user.firstName

String

Yes

User’s first name

-

Any string

user.lastName

String

No

User’s last name

nil

Any string

user.email

String

No

User’s email

nil

Any string

onSuccess

Function

No

Callback on success with liveness data

nil

Any function

onFailure

Function

No

Callback on failure with error data

nil

Any function

sandboxEnvironment

Bool

No

Toggle sandbox mode for testing

true

true, false


Available Tasks

Tasks verify liveness through user interactions. Below are the supported options:

Complete The Circle

Users trace a circle with head movements.

Option
Type
Required
Description
Default
Values

difficulty

TaskDifficulty

No

Task difficulty

.medium

.easy, .medium, .hard

timeout

Number

No

Time (ms) before task fails

nil

Any milliseconds

Example:

TaskProperties(task: .completeTheCircle(CompleteTheCircleTask(difficulty: .medium)))

Yes or No

Users answer questions by tilting their head (right = yes, left = no).

Option
Type
Required
Description
Default
Values

difficulty

TaskDifficulty

No

Task difficulty

.medium

.easy, .medium, .hard

timeout

Number

No

Time (ms) before task fails

nil

Any milliseconds

questions

Array

Yes

List of yes/no questions

-

See below

questions.question

String

Yes

Yes/no question

-

Any string

questions.answer

Bool

Yes

Correct answer

-

true, false

questions.errorMessage

String

No

Message on wrong answer

nil

Any string

Example:

TaskProperties(task: .yesOrNo(YesOrNoTask(questions: [YesOrNoQuestion(question: "Is 2 + 2 = 7?", answer: false)])))

Motions

Users perform nods, blinks, or mouth movements.

Option
Type
Required
Description
Default
Values

difficulty

TaskDifficulty

No

Task difficulty

.medium

.easy, .medium, .hard

timeout

Number

No

Time (ms) before task fails

nil

Any milliseconds

maxNods

Int

No

Max nods to perform

5

Any number

maxBlinks

Int

No

Max blinks to perform

5

Any number

Example:

TaskProperties(task: .motions(MotionsTaskClass(difficulty: .medium)))

Liveness Data

The onSuccess callback returns:

Field
Type
Description

faceImage

String

User’s face image

livenessClip

String

Video of liveness check

passed

Bool

True if passed, false if failed

metadata

Any

Metadata from initialization

The onFailure callback returns error details as a string or object, depending on the issue.


Full Example

Here’s the complete implementation from the working code:

import UIKit
import YouverifyLivenessSDK

class MainViewController: UIViewController {
    private var yvLiveness = YVLiveness(
        publicKey: Environment.shared.value(forKey: "API_KEY") ?? "",
        user: YVLivenessUser(firstName: "Ugochukwu"),
        onSuccess: { data in
            print("The success data is \(data)")
        },
        onFailure: { errorData in
            print("The error data is \(errorData)")
        },
        sandboxEnvironment: false
    )
    
    private var livenessViewController: YVLivenessViewController?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Create a vertical stack view
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 10
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        // Create buttons
        let completeCircleButton = createButton(title: "Complete the Circle", action: #selector(completeTheCircleTapped))
        let yesOrNoButton = createButton(title: "Yes or No", action: #selector(yesOrNoTapped))
        let motionsButton = createButton(title: "Motions", action: #selector(motionsTapped))
        let passiveLivenessButton = createButton(title: "Passive Liveness", action: #selector(passiveLivenessTapped))
        
        // Add buttons to stack view
        stackView.addArrangedSubview(completeCircleButton)
        stackView.addArrangedSubview(yesOrNoButton)
        stackView.addArrangedSubview(motionsButton)
        stackView.addArrangedSubview(passiveLivenessButton)
        
        // Add stack view to the main view
        view.addSubview(stackView)
        
        // Set Auto Layout constraints
        NSLayoutConstraint.activate([
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
        ])
    }
    
    private func addLivenessViewController() {
        guard livenessViewController == nil else { return } // Prevent duplicate adds
        let vc = YVLivenessViewController(sdk: yvLiveness)
        vc.delegate = self
        
        addChild(vc)
        
        view.addSubview(vc.view)
        vc.didMove(toParent: self)
        livenessViewController = vc
    }

    private func removeLivenessViewController() {
        guard let vc = livenessViewController else { return }
        vc.willMove(toParent: nil)
        vc.view.removeFromSuperview()
        vc.removeFromParent()
        livenessViewController = nil
    }
    
    // Helper function to create buttons with actions
    private func createButton(title: String, action: Selector) -> UIButton {
        let button = UIButton(type: .system)
        button.setTitle(title, for: .normal)
        button.addTarget(self, action: action, for: .touchUpInside)
        return button
    }
    
    // MARK: - Button Actions
    
    private func startLiveness(with tasks: [TaskProperties]) {
        yvLiveness.startSDK(tasks: tasks)
        DispatchQueue.main.async {
            self.addLivenessViewController()
        }
    }
    
    @objc private func completeTheCircleTapped() {
        startLiveness(with: [
            TaskProperties(task: .completeTheCircle(CompleteTheCircleTask(difficulty: .medium)))
        ])
    }
    
    @objc private func yesOrNoTapped() {
        startLiveness(with: [TaskProperties(
            task: .yesOrNo(YesOrNoTask(questions: [YesOrNoQuestion(question: "Is 2 + 2 = 7?", answer: false)]))
        )])
    }
    
    @objc private func motionsTapped() {
        startLiveness(with: [TaskProperties(
            task: .motions(MotionsTaskClass(difficulty: .medium))
        )])
    }
    
}

extension MainViewController: YVLivenessViewDelegate {
    func closeModal() {
        DispatchQueue.main.async {
            self.removeLivenessViewController()
        }
    }
}

Credits

This SDK is developed and maintained solely by Youverify

Last updated

Was this helpful?