Skip to content

iOS SDK Integration ​

Integration guide for the eKYC iOS SDK, version 1.1.9. Written in Swift; the entry point is the CakeEkycSdk class.

Build Specifications ​

WhatDescription
Xcode16.0+
Target iOS version13+
Swift5

Setup Dependencies ​

Add the *.framework files to your target, then declare the camera permission:

xml
<key>NSCameraUsageDescription</key>
<string>Camera access helps us give you a better experience</string>

Add these pods:

ruby
pod 'TensorFlowLiteSwift', '2.6.0'
pod 'GoogleMLKit/FaceDetection', '6.0.0'
pod 'PromisesSwift', '~> 2.3.1'
pod 'SnapKit', '~> 5.0.1'

Initialize and Configure ​

CakeEkycSdk.getInstance returns a Future<CakeEkycSdk, Never>.

swift
let config = CESConfig.Builder()
    .withBaseUrl(url: "<BASE_URL>")
    .withToken(tokenProvider: tokenProvider)
    .withLanguage(language: .vi)
    .withLogger(logger: logger)
    .build()

self.cancelable = CakeEkycSdk.getInstance(config: config)
    .receive(on: DispatchQueue.main)
    .sink { [weak self] ekycSdk in
        self?.ekycSdk = ekycSdk
    }

Take NID Card ​

Conform to CESNidCapturingDelegate and call takeNid.

swift
class YourUIViewController: UIViewController, CESNidCapturingDelegate {
    func onSuccess(result: CESNidCardResult) {}

    func onError(error: CESError) {}

    func onEvent(event: CESEkycEvent) {}

    private func startTakeNid() {
        guard let ekycSdk else { return }
        let config = CESTakeNidConfig(
            cardType: .cccd,
            cardSides: [.front, .back],
            requiredReview: true,
            autoCaptureEnable: true,
            requiredScanQR: false,
            captureOnly: false,
            loadingView: loadingView
        )
        ekycSdk.takeNid(hostViewController: self, config: config, delegate: self)
    }
}

Passing the other side ​

swift
let frontSide: CESEkycImage

ekyc.takeNid(
    hostViewController: self,
    config: CESTakeNidConfig(
        cardSides: [CESCardSide.back],
        otherSideImages: [CESCardSide.front: frontImage]
    ),
    delegate: self
)

Errors ​

FieldTypeDescription
CESError.userCancelled40001User pressed back.
CESError.timeoutError40000Timeout.
CESError.permissionNotGranted40002Permissions were not granted.
CESError.qualityFailed60000 / 60001kErrorCodeNidSanityFailed or kErrorCodeNidTamperingFailed.
CESError.unexpectedError50000Runtime exception.

INFO

The iOS SDK has no camera-specific error code. 40003 (CameraError) exists only on Android and Flutter — camera failures on iOS surface as unexpectedError.

Take Faces ​

swift
class YourUIViewController: UIViewController, CESFaceCapturingDelegate {
    func onSuccess(result: CESSelfieResult) {}

    func onError(error: CESError) {}

    func onEvent(event: CESEkycEvent) {}

    private func startFace() {
        guard let ekycSdk else { return }
        let config = CESTakeFaceConfig(captureOnly: false, loadingView: loadingView)
        ekycSdk.takeFaces(hostViewController: self, config: config, delegate: self)
    }
}

Quality failures here carry kErrorCodeFaceSanityFailed (60002) or kErrorCodeFaceLivenessFailed (60003).

Custom Loading UI ​

Pass your own UIView to CESTakeNidConfig.loadingView or CESTakeFaceConfig.loadingView to replace the SDK's loading screen during upload and quality checks.

Upload Image ​

swift
let uploadResult = ekycSdk.upload(image: image, label: label, metaData: metaData)
switch uploadResult {
case .success(data: let uploadResponse):
    debugPrint("success: \(uploadResponse.data?.imageId)")
case .fail(error: let error):
    debugPrint("fail: \(error)")
default: fatalError()
}

Data is also accepted: ekycSdk.upload(data: data, label: label, metaData: metaData).

See Mobile SDK Overview § Image Labels for permitted label values.

Individual API Calls ​

Each takes a params struct and returns CESResult<CESEkycResponse<T>>.

swift
// Sanity — both sides, or pass image only for one side
let params = CESCheckNidSanityParams(
    image: frontNIDImageId,
    image2: backNIDImageId,
    cardType: "vn.national_id",
    specialTypeId: ""
)
let sanityResult = ekycSdk.checkNidSanity(params: params)

switch sanityResult {
case .success(data: let sanityResponse):
    debugPrint("success: \(sanityResponse.data?.cardSanityData)")
case .fail(error: let error):
    debugPrint("fail: \(error)")
default: fatalError()
}
swift
let tamperingResult = ekycSdk.checkNidTampering(params: CESCheckNidTamperingParams(
    image: frontNIDImageId, image2: backNIDImageId, cardType: "vn.national_id", level: nil))

let readNidResult = ekycSdk.readNidInfo(params: CESNidReadInfoParams(
    image: frontNIDImageId, image2: backNIDImageId, cardType: "vn.national_id"))

let faceSanity   = ekycSdk.checkFaceSanity(params: CESFaceSanityParams(image: "face_image_id"))
let faceLiveness = ekycSdk.checkFaceLiveness(params: CESFaceLivenessParams(images: ["face_image_id"]))
let compared     = ekycSdk.compareFaces(params: CESFaceCompareParams(image1: "face_1", image2: "face_2"))
MethodAPI
checkNidSanityVerify ID Card Sanity
checkNidTamperingDetect ID Card Tampering
readNidInfoRead ID Card Info
checkFaceSanityVerify Face Sanity
checkFaceLivenessVerify Face Liveness
compareFacesCompare Faces

INFO

CESFaceLivenessParams takes images: [String] — pass an array, not a single image.

Next Steps ​

Developers