Liveness
In the liveness step the user records a short video with the front camera. Prove ID checks the video for liveness and compares the face with the document photo.
Liveness with a gesture
Section titled “Liveness with a gesture”The gestureType returned when the transaction started decides which gesture the user is asked for.
import UIKitimport RKYC_iOS
final class LivenessViewController: UIViewController { @IBOutlet weak var containerView: UIView!
private let livenessController = LivenessController()
override func viewDidLoad() { super.viewDidLoad()
LivenessController.FACE_DETECTION_LAYER_SHAPE = .OVAL LivenessController.CONTROL_FACE_CAPTURE = true LivenessController.STOP_VIDEO_WHILE_RECORDING = true LivenessController.GESTURE_TYPE = .EYE // .EYE, .MOUTH, .HEAD_VERTICAL, .HEAD_HORIZONTAL LivenessController.IS_GESTURE_CONTROL_ENABLED = true LivenessController.VIDEO_PREPARATION_TIME_IN_SECONDS = 3 LivenessController.VIDEO_TIME_IN_SECONDS = 5
livenessController.setDelegate(self) livenessController.setGestureDelegate(self) containerView.addSubview(livenessController.view) }
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) livenessController.startCapture() }}
extension LivenessViewController: LivenessDelegate, GestureDelegate { func gestureControlled(gestureModel: GestureModel) { livenessController.stopCapture() // Send gestureModel.videoURL and gestureModel.rotate (below) }
func onVideoCaptured(videoURL: URL, rotate: Int) { // Called without gesture control (passive liveness) }
func onVideoStarting() { /* show a countdown */ } func onVideoStarted() { } func onVideoCanceled() { /* the face left the frame; ask the user to try again */ } func onFaceDetectionFailure(isAway: Bool) { /* isAway: move closer, otherwise move away */ } func onFaceDetectionSuccess() { } func onFaceDetectionIdle() { } func onMultiFaceDetected() { /* only one person in the frame */ }
func positionFailed(model: PositionFailedModel) { } func positionSucceed(model: PositionSuccedModel) { } func positionCorrect() { } func preparationPositionControlled(model: PreparationPositionModel) { }}gestureType values and their GestureType counterparts:
gestureType |
LivenessController.GESTURE_TYPE |
|---|---|
EYE |
.EYE |
MOUTH |
.MOUTH |
HEAD-VERTICAL |
.HEAD_VERTICAL |
HEAD-HORIZONTAL |
.HEAD_HORIZONTAL |
MULTIDIR_… |
.RANDOMIZED_MULTI_GESTURE |
For head gestures, gestureModel.gestureScore tells you how well the gesture was made; ask the user to try again when it is low (e.g. below 0.8) and call startCapture() again.
Multiple head directions
Section titled “Multiple head directions”A gestureType starting with MULTIDIR_ asks the user to turn their head in several directions in a row. The directions follow the prefix, separated by -; pass them to the SDK as HeadPosition values:
let directions = gestureType.dropFirst("MULTIDIR_".count).split(separator: "-")
LivenessController.GESTURE_TYPE = .RANDOMIZED_MULTI_GESTURELivenessController.RANDOMIZED_GESTURES = directions.compactMap { HeadPosition(string: String($0)) }LivenessController.IS_GESTURE_CONTROL_ENABLED = trueLivenessController.VIDEO_PREPARATION_TIME_IN_SECONDS = 0Send the video
Section titled “Send the video”import ProveIDApiClient
guard let video = try? Data(contentsOf: gestureModel.videoURL) else { return }
let body = FaceVerificationModel(transactionId: transactionId, video: video.base64EncodedString(), rotate: gestureModel.rotate)
FaceServiceAPI.verifyFace(body: body) { result in switch result { case .success(let response): let controls = response.controlResults showLivenessResult(controls) case .failure(let error): showError(error) }}
try? FileManager.default.removeItem(at: gestureModel.videoURL) // don't leave the video on the devicePassive liveness
Section titled “Passive liveness”Works without a gesture, with a short recording. The video arrives in onVideoCaptured(videoURL:rotate:); send it the same way.
LivenessController.IS_GESTURE_CONTROL_ENABLED = falseLivenessController.VIDEO_PREPARATION_TIME_IN_SECONDS = 1LivenessController.VIDEO_TIME_IN_SECONDS = 2Liveness from a photo
Section titled “Liveness from a photo”With a single photo instead of a video:
LivenessController.LIVENESS_FROM_IMAGE_ENABLED = truelivenessController.setLivenessPhotoDelegate(self)
extension LivenessViewController: LivenessPhotoDelegate { func photoCaptured(image: UIImage) { livenessController.stopCapture()
let body = FaceVerificationWithImageInputModel(transactionId: transactionId, image: image.pngData()!.base64EncodedString()) FaceServiceAPI.verifyFaceWithImage(body: body) { result in /* same as verifyFace */ } }
func eligiblePositionForCapture(model: PreparationPositionModel) { }}Liveness with the ID card
Section titled “Liveness with the ID card”With the LivenessWithCard module the user’s face and the front of their ID card are captured together, and the face is matched with the card photo.
import LivenessWithCard
LWICController.CARD_CAPTURE_ENABLED = trueLWICController.LIVENESS_FROM_IMAGE_ENABLED = trueLWICController.FACE_DETECTION_LAYER_SHAPE = .OVAL
let lwicController = LWICController()lwicController.cardType = .NEW_IDlwicController.setDelegate(self)lwicController.setCardDelegate(self)lwicController.setPhotoDelegate(self)containerView.addSubview(lwicController.view)lwicController.startCapture()Send the captured image:
let body = CheckLivenessWithCardImageInputModel(transactionId: transactionId, imageBase64: image.pngData()!.base64EncodedString(), livenessProcessStage: "FACEANDFRONT")
IDServiceAPI.checkLivenessWithIdCardImage(body: body) { result in /* … */ }Start the transaction with the LIVENESS_WithIdCard control for this step. The face match is reported in the LWICONLYFRONTFACESIMILARITY control.
Settings
Section titled “Settings”| Setting | Description |
|---|---|
FACE_DETECTION_LAYER_SHAPE |
Shape of the face frame (.OVAL) |
CONTROL_FACE_CAPTURE |
Records only while a face is in the frame |
STOP_VIDEO_WHILE_RECORDING |
Cancels the recording if the face leaves the frame |
FACE_OVER_SCREEN_RATIO |
Size of the face frame relative to the screen (e.g. 0.6) |
FACE_AWAY_CHECK_RATIO |
How far the face may be before isAway is reported |
GESTURE_TYPE |
Gesture to ask for |
IS_GESTURE_CONTROL_ENABLED |
Checks the gesture on the device |
HEAD_HORIZONTAL_MAX_PREP_THRESHOLD, HEAD_VERTICAL_MAX_PREP_THRESHOLD |
Head angle allowed before recording starts (e.g. 15) |
VIDEO_PREPARATION_TIME_IN_SECONDS |
Countdown before recording |
VIDEO_TIME_IN_SECONDS |
Recording length |
LIVENESS_FROM_IMAGE_ENABLED |
Takes a photo instead of a video |