iOS SDK Reference
Complete public API surface for the iLive iOS SDK.
iOS SDK Reference
This page documents the public Swift API of the iLive iOS SDK: entry points, configuration, result types, and face comparison helpers. For a step-by-step integration walkthrough, see the iOS quickstart.
Installation
The SDK ships as two Swift targets: ILiveCore (engine, configuration, results) and ILiveUI (drop-in LivenessViewController). Both are distributed via Swift Package Manager and CocoaPods. See the quickstart for full setup.
Minimum deployment target: iOS 14.0.
Entry points
There are two ways to run a liveness session:
- Drop-in UI —
LivenessViewControllerfromILiveUI. A full-screenUIViewControllerthat handles camera, guidance, challenges, and the result screen. SwiftUI callers can wrap it withUIViewControllerRepresentable. - Custom UI —
LivenessEnginefromILiveCore. You drive the camera and UI; the engine consumesCVPixelBufferframes and returns a verdict.
Top-level helpers live on the ILive class:
| Member | Signature | Purpose |
|---|---|---|
version | static let String | SDK version string. |
isDeviceSupported | static func isDeviceSupported() -> DeviceSupportResult | Checks OS version. |
compareFaces | static func compareFaces(reference: Data, probe: Data, threshold: Float = 0.45) -> FaceMatchResult? | 1:1 comparison of two JPEGs. |
compareFaceWithEmbedding | static func compareFaceWithEmbedding(referenceEmbedding: [Float], probe: Data, threshold: Float = 0.45) -> FaceMatchResult? | Compare a stored embedding against a new JPEG. |
Drop-in UI: LivenessViewController
LivenessViewController is a plain UIViewController. Create it, set result callbacks, then present it modally.
| Initializer / property | Signature | Notes |
|---|---|---|
init(config:passiveMode:) | convenience init(config: ILiveConfig = ILiveConfig(), passiveMode: Bool = true) | Passive mode runs without user challenges. |
onResult | ((LivenessResult) -> Void)? | Fired with the final LivenessResult. |
onDismiss | (() -> Void)? | Fired after the controller dismisses itself. |
For SwiftUI, wrap it with UIViewControllerRepresentable:
Custom UI: LivenessEngine
LivenessEngine exposes the capture pipeline without a bundled UI.
| Method | Signature | Notes |
|---|---|---|
| Create | static func create(config: ILiveConfig = ILiveConfig()) async -> LivenessEngine | Async factory. |
| Initialize | func initialize() async | Loads on-device models. Call once before processFrame. |
| Process frame | func processFrame(pixelBuffer: CVPixelBuffer) -> TrackingResult | Feed every camera frame. |
| Start challenges | func startChallenges(delegate: ChallengeEventDelegate) | Begin the interactive challenge sequence. |
| Evaluate (active) | func evaluateVerdict() async -> LivenessResult | Call after all challenges complete. |
| Evaluate (passive) | func evaluatePassiveVerdict() async -> LivenessResult | Skips challenges; scores purely from captured frames. |
| Release | func release() | Free resources. Idempotent. |
sessionId | String | UUID for this session. |
currentStage | LivenessStage | .initializing, .ready, .challenges, .processing, .result. |
Configuration: ILiveConfig
ILiveConfig is a value type with a memberwise initializer — pass only the fields you want to override.
Challenges and verdict thresholds
| Field | Type | Default | Description |
|---|---|---|---|
challengeCount | Int | 3 | Number of challenges in active mode. |
challengeTypes | Set<ChallengeType> | ILiveConfig.defaultChallengeTypes (7 of 8) | Pool of challenges to draw from. Excludes .eyeFollow by default — see note below. |
challengeTimeoutSeconds | Int | 8 | Per-challenge timeout. |
transitionDelayMs | Int | 500 | Pause between challenges. |
maxRetriesPerChallenge | Int | 1 | In-session retry count per challenge. |
passThreshold | Float | 0.70 | Minimum confidence for .pass. |
retryThreshold | Float | 0.45 | Minimum confidence for .retry. |
antispoofFloor | Float | 0.30 | Anti-spoof layer veto floor. |
deepfakeFloor | Float | 0.20 | Deepfake layer veto floor. |
layerWeights | LayerWeights | balanced | Per-layer weight vector. |
ChallengeType values: .blink, .turnLeft, .turnRight, .nod, .smile, .mouthOpen, .eyebrowRaise, .eyeFollow.
eyeFollowon iOS. The drop-inLivenessViewControllerdoes not currently render the moving-dot overlay that this challenge needs. To avoid showing users a prompt with no visible target,.eyeFollowis omitted fromILiveConfig.defaultChallengeTypes. The enum case is still public so sessions that ran with earlier defaults continue to compile, and callers who supply a custom UI can opt in by passing it explicitly inchallengeTypes— the SDK emits anos_logwarning when they do.eyeFollowremains fully supported on Android and Flutter; iOS parity will land when the overlay ships.
Voice prompts
| Field | Type | Default | Description |
|---|---|---|---|
voicePromptsEnabled | Bool | false | Speak challenge instructions. |
voiceRate | Float | 1.0 | Speech rate multiplier. |
voiceLanguage | String | "en-US" | BCP-47 locale tag. |
Photo extraction
| Field | Type | Default | Description |
|---|---|---|---|
photoExtractionEnabled | Bool | true | Produce an ICAO-style still on .pass. |
photoWidth | Int | 480 | Output width. |
photoHeight | Int | 600 | Output height. |
photoJpegQuality | Int | 95 | JPEG quality (0–100). |
Security
| Field | Type | Default | Description |
|---|---|---|---|
attestationKeyBase64 | String? | nil | Base64-encoded HMAC key used to sign the result payload. Canonical form across all SDKs. |
attestationKey | Data? (deprecated) | nil | Deprecated raw-bytes field, retained for one release. Prefer attestationKeyBase64. |
frameBundleEncryptionKey | Data? | nil | AES key (32 bytes) used to encrypt captured frames. |
frameBundleFrameCount | Int | 8 | Number of frames in the encrypted bundle. |
Timeouts
| Field | Type | Default |
|---|---|---|
modelLoadTimeoutSeconds | Int | 10 |
cameraInitTimeoutSeconds | Int | 5 |
totalSessionTimeoutSeconds | Int | 120 |
Results: LivenessResult
Returned by evaluateVerdict() and evaluatePassiveVerdict(), and delivered via LivenessViewController.onResult.
| Field | Type | Description |
|---|---|---|
sessionId | String | UUID assigned when the engine was created. |
verdict | Verdict | .pass, .fail, or .retry. |
confidence | Float | Weighted aggregate confidence (0.0–1.0). |
layerScores | [LayerScore] | Per-layer breakdown. |
retryHint | String? | User-facing guidance when verdict == .retry. |
failureReason | String? | Diagnostic reason when verdict == .fail. |
icaoPhoto | Data? | JPEG still of the subject on .pass. |
photoQualityScore | Float? | Quality rating for icaoPhoto (0.0–1.0). |
faceEmbedding | [Float]? | 512-dimensional face embedding from the best frame. |
attestation | Attestation? | Signed payload (payload, signature, algorithm) when attestationKeyBase64 was set. |
encryptedFrameBundle | FrameBundle? | Encrypted captured frames (ciphertext, iv, frameCount, keyId). |
metadata | SessionMetadata | Duration, challenge timings, device model, OS version, SDK version. |
Face recognition: ILive.compareFaces()
One-shot 1:1 face comparison. Returns nil if an image cannot be decoded or no face is found.
FaceMatchResult: similarity: Float (cosine similarity, 0.0–1.0), isMatch: Bool (similarity >= threshold), threshold: Float.
Error handling
The engine does not throw on evaluation — instead, failures surface via LivenessResult.verdict == .fail with failureReason set. Common reasons:
| Reason | Meaning |
|---|---|
"Engine released" | evaluate* was called after release(). |
"No face detected" | No face was found across captured frames. |
"Session timeout" | The session exceeded totalSessionTimeoutSeconds. |
"Antispoof floor" / "Deepfake floor" | A hard-floor layer vetoed the verdict. |
Camera permission is the caller's responsibility — ensure NSCameraUsageDescription is set and permission is granted before presenting LivenessViewController.