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:
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 prevent linker errors, add the following post-install script to your application's Podfile, making sure to replace "YourAppTarget"
with the correct target name for your app.
post_install do |installer| target_name = "YourAppTarget"
# Get the paths to the xcconfig files
debug_xcconfig_path = "#{installer.pods_project.project_dir}/Target Support Files/Pods-#{target_name}/Pods-#{target_name}.debug.xcconfig"
release_xcconfig_path = "#{installer.pods_project.project_dir}/Target Support Files/Pods-#{target_name}/Pods-#{target_name}.release.xcconfig"
# Modify the debug .xcconfig file if it exists
if File.exist?(debug_xcconfig_path)
puts "Modifying debug .xcconfig file: #{debug_xcconfig_path}"
# Read the debug .xcconfig file
debug_xcconfig = File.read(debug_xcconfig_path)
# Remove framework flags from OTHER_LDFLAGS
debug_xcconfig.gsub!(/-framework\s+"MediaPipeTasksCommon"/, '')
debug_xcconfig.gsub!(/-framework\s+"MediaPipeTasksVision"/, '')
# Remove -force_load from OTHER_LDFLAGS for iphoneos and iphonesimulator
debug_xcconfig.gsub!(/-force_load\s+"?[^"]*libMediaPipeTasksCommon.*\.a"?/, '')
# Write the modified debug .xcconfig file
File.write(debug_xcconfig_path, debug_xcconfig)
puts "Modified debug .xcconfig file."
else
puts "Debug .xcconfig file not found at #{debug_xcconfig_path}"
end
# Modify the release .xcconfig file if it exists
if File.exist?(release_xcconfig_path)
puts "Modifying release .xcconfig file: #{release_xcconfig_path}"
# Read the release .xcconfig file
release_xcconfig = File.read(release_xcconfig_path)
# Remove framework flags from OTHER_LDFLAGS
release_xcconfig.gsub!(/-framework\s+"MediaPipeTasksCommon"/, '')
release_xcconfig.gsub!(/-framework\s+"MediaPipeTasksVision"/, '')
# Remove -force_load from OTHER_LDFLAGS for iphoneos and iphonesimulator
release_xcconfig.gsub!(/-force_load\s+"?[^"]*libMediaPipeTasksCommon.*\.a"?/, '')
# Write the modified release .xcconfig file
File.write(release_xcconfig_path, release_xcconfig)
puts "Modified release .xcconfig file."
else
puts "Release .xcconfig file not found at #{release_xcconfig_path}"
end
end
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 afirstName
, while optional fields likelastName
andemail
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 inaddLivenessViewController()
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
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.
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).
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.
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:
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?