Skip to main content
Este guia mostra a API pública do LivenessFacetecSDK para iOS e o fluxo completo de uma verificação de vivacidade.

API pública

A fachada do SDK fica em LivenessFacetecSDKClient.shared:
@MainActor
public final class LivenessFacetecSDKClient {
    public static let shared: LivenessFacetecSDKClient

    public var isInitialized: Bool

    public func initialize(config: LivenessFacetecSDKConfig) async throws -> LivenessFacetecSDKInitResult

    public func startLivenessCheck(
        viewController: UIViewController,
        sessionId: String,
        sessionToken: String,
        facetecSessionToken: String
    ) -> AsyncStream<LivenessFacetecSDKLivenessState>

    public func stop()
}
  • initialize é assíncrona, retorna LivenessFacetecSDKInitResult com dados de fingerprint. Verifique isInitialized antes de chamar — para reinicializar (ex.: troca de ambiente ou logout), chame stop() antes de um novo initialize().
  • startLivenessCheck requer uma UIViewController e os três tokens de sessão criados pelo consumidor via POST /api/v1/sessions.
  • stop() libera o estado interno do SDK. Não chamar enquanto uma captura estiver em progresso.
  • isInitialized indica se initialize foi concluído com sucesso.

Configuração

public struct LivenessFacetecSDKConfig {
    public let customization: LivenessFacetecSDKCustomization?

    public init(customization: LivenessFacetecSDKCustomization? = nil)
}
ParâmetroTipoObrigatórioDescrição
customizationLivenessFacetecSDKCustomization?NãoPersonalização da UI do FaceTec. Veja Customização

Estados do AsyncStream

startLivenessCheck retorna um AsyncStream<LivenessFacetecSDKLivenessState> que emite um único caminho loading → success ou loading → error antes de completar:
public enum LivenessFacetecSDKLivenessState {
    case loading
    case success(LivenessFacetecSDKResultData)
    case error(LivenessFacetecSDKError)
}

Fluxo de uso

1

Inicializar o SDK

Chame LivenessFacetecSDKClient.shared.initialize uma única vez no início do ciclo de vida do app (preferencialmente no AppDelegate). O método retorna LivenessFacetecSDKInitResult com os dados de fingerprint — armazene-os para usá-los ao criar a sessão:
import LivenessFacetecSDK
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var initResult: LivenessFacetecSDKInitResult?

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        Task {
            do {
                let config = LivenessFacetecSDKConfig()
                self.initResult = try await LivenessFacetecSDKClient.shared.initialize(config: config)
            } catch let error as LivenessFacetecSDKInitError {
                switch error {
                case .alreadyInitialized:
                    break
                case .provisioningFailed(let msg):
                    print("Provisioning failed: \(msg)")
                case .facetecInitializationFailed(let msg):
                    print("FaceTec init failed: \(msg)")
                }
            }
        }

        return true
    }
}
2

Criar sessão no backend

Antes de iniciar o liveness check, crie uma sessão com os dados de fingerprint do LivenessFacetecSDKInitResult
3

Iniciar a verificação

Passe os tokens de sessão obtidos no passo anterior:
import LivenessFacetecSDK
import UIKit

final class VerificationViewController: UIViewController {

    func iniciarLiveness(sessionId: String, sessionToken: String, facetecSessionToken: String) {
        Task {
            let stream = LivenessFacetecSDKClient.shared.startLivenessCheck(
                viewController: self,
                sessionId: sessionId,
                sessionToken: sessionToken,
                facetecSessionToken: facetecSessionToken
            )

            for await state in stream {
                await MainActor.run {
                    switch state {
                    case .loading:
                        mostrarProgresso()

                    case .success(let data):
                        tratarSucesso(data)

                    case .error(let error):
                        tratarErro(error)
                    }
                }
            }
        }
    }
}
4

Tratar o resultado

No caso de sucesso, use sessionId e captureId para reconciliar a captura no backend. No caso de erro, mapeie cada caso de LivenessFacetecSDKError para uma mensagem ou ação adequada — veja Solução de problemas.

Parar e reinicializar o SDK

stop() libera o estado interno do SDK e permite uma nova chamada a initialize(). Use quando precisar trocar de ambiente, realizar logout com limpeza de estado, ou isolar estado entre testes.
// Verificar estado
print(LivenessFacetecSDKClient.shared.isInitialized) // true após initialize com sucesso

// Teardown — aguarde o stream de startLivenessCheck encerrar antes de chamar
LivenessFacetecSDKClient.shared.stop()
print(LivenessFacetecSDKClient.shared.isInitialized) // false

// Reinicialização — comporta-se como primeira vez
let result = try await LivenessFacetecSDKClient.shared.initialize(config: config)
Não chame stop() enquanto uma captura estiver em progresso. Aguarde o stream de startLivenessCheck encerrar (.success ou .error) antes de chamar.

Campos de LivenessFacetecSDKResultData

Quando a verificação termina com sucesso, o SDK emite .success(LivenessFacetecSDKResultData):
CampoTipoDescrição
sessionIdStringID da sessão criada no backend da Plataforma ID
captureIdStringID único da captura submetida
statusStringStatus final da captura
processedAtStringTimestamp ISO-8601 do processamento
resultString?Resultado do Liveness
scanResultBlobString?Blob bruto retornado pelo FaceTec
transactionIdString?ID da transação no provedor
retryScreenInt?Indicador interno de retry
replayCheckBoolResultado da verificação anti-replay
sessionTokenCheckBoolValidação do token de sessão
auditTrailCheckBoolValidação da trilha de auditoria
livenessCheckBoolResultado da verificação de vivacidade
Os quatro campos *Check são as garantias de segurança consolidadas pelo backend. Em uma captura legítima, todos devem ser true.

Erros possíveis

LivenessFacetecSDKInitError

Lançados por initialize(config:):
CasoCausa
alreadyInitializedinitialize() foi chamado enquanto o SDK já estava inicializado. Verifique isInitialized antes de chamar, ou chame stop() para reinicializar.
provisioningFailed(String)Falha nas chaves internas — blob corrompido ou chaves ausentes no build. A mensagem associada contém diagnóstico.
facetecInitializationFailed(String)FaceTec SDK rejeitou as chaves internas. A mensagem associada contém diagnóstico do FaceTec.

LivenessFacetecSDKError

Emitidos como .error(LivenessFacetecSDKError) pelo AsyncStream:
CasoCausa
captureError(String)Erro interno durante a captura FaceTec
submitError(String)Falha ao enviar os dados de captura para o backend
networkError(String)Erro de rede (timeout, sem conectividade)
cancelledUsuário fechou a tela de captura
unknown(String)Erro inesperado
A hierarquia completa, com causa provável e ação recomendada para cada caso, está em Solução de problemas.

Exemplos de retorno

Sucesso — liveness aprovado

O fluxo terminou e a verificação biométrica passou. status vem "completed", result é "live" e todos os *Check são true.
.success(
    LivenessFacetecSDKResultData(
        sessionId: "8f3a9c10-2b7d-4e1f-9c2a-5d6e7f8a9b01",
        captureId: "1c4e5f60-3a2b-4d8e-9f10-7b6c5d4e3f21",
        status: "completed",
        processedAt: "2026-04-28T14:32:18.421Z",
        result: "live",
        scanResultBlob: "...",
        transactionId: "txn_abc123def456",
        retryScreen: nil,
        replayCheck: true,
        sessionTokenCheck: true,
        auditTrailCheck: true,
        livenessCheck: true
    )
)

Sucesso — liveness reprovado

O fluxo terminou tecnicamente, mas o resultado biométrico foi negativo. status vem "failed", result é "not_live" e livenessCheck é false.
.success(
    LivenessFacetecSDKResultData(
        sessionId: "8f3a9c10-2b7d-4e1f-9c2a-5d6e7f8a9b01",
        captureId: "9d8c7b6a-5e4f-3d2c-1b0a-9f8e7d6c5b4a",
        status: "failed",
        processedAt: "2026-04-28T14:35:02.108Z",
        result: "not_live",
        scanResultBlob: "...",
        transactionId: "txn_xyz789ghi012",
        retryScreen: 2,
        replayCheck: true,
        sessionTokenCheck: true,
        auditTrailCheck: false,
        livenessCheck: false
    )
)
Esse caso não é erro técnico — o SDK funcionou corretamente, mas a prova de vida foi reprovada. Trate como negativa de verificação no seu app (mostrar mensagem ao usuário e permitir nova tentativa), sem reportar como falha do SDK.

Erro do fluxo

Quando algo no fluxo técnico falha, o SDK emite .error(LivenessFacetecSDKError):
// Sem conectividade ou timeout HTTP
.error(.networkError("Connection timed out"))

// Falha durante a captura biométrica
.error(.captureError("FaceTec session timed out"))

// Usuário fechou a UI do FaceTec
.error(.cancelled)

Exemplo completo (SwiftUI)

import SwiftUI
import LivenessFacetecSDK

struct LivenessView: View {
    @State private var isLoading = false
    @State private var resultMessage: String?

    // initResult deve ser passado pelo nível superior após initialize()
    let initResult: LivenessFacetecSDKInitResult

    var body: some View {
        VStack(spacing: 24) {
            Button(action: iniciarLiveness) {
                HStack {
                    if isLoading {
                        ProgressView().tint(.white)
                    }
                    Text(isLoading ? "Verificando..." : "Iniciar Liveness")
                }
                .frame(maxWidth: .infinity)
                .padding()
                .background(Color.accentColor)
                .foregroundColor(.white)
                .cornerRadius(12)
            }
            .disabled(isLoading)

            if let message = resultMessage {
                Text(message).multilineTextAlignment(.center)
            }
        }
        .padding()
    }

    private func iniciarLiveness() {
        guard let viewController = UIApplication.shared
            .connectedScenes
            .compactMap({ ($0 as? UIWindowScene)?.keyWindow?.rootViewController })
            .first
        else { return }

        isLoading = true
        resultMessage = nil

        Task {
            // 1. Criar sessão no backend com os dados de fingerprint
            guard let tokens = try? await criarSessao(initResult: initResult) else {
                await MainActor.run {
                    isLoading = false
                    resultMessage = "Erro ao criar sessão."
                }
                return
            }

            // 2. Iniciar liveness com os tokens de sessão
            let stream = LivenessFacetecSDKClient.shared.startLivenessCheck(
                viewController: viewController,
                sessionId: tokens.sessionId,
                sessionToken: tokens.sessionToken,
                facetecSessionToken: tokens.facetecSessionToken
            )

            for await state in stream {
                await MainActor.run {
                    switch state {
                    case .loading:
                        resultMessage = "Processando..."

                    case .success(let data):
                        isLoading = false
                        resultMessage = """
                        Sucesso!
                        Session: \(data.sessionId)
                        Capture: \(data.captureId)
                        Status: \(data.status)
                        Liveness: \(data.livenessCheck)
                        """

                    case .error(let error):
                        isLoading = false
                        resultMessage = "Erro: \(error)"
                    }
                }
            }
        }
    }
}

Próximos passos

Customização

Personalize cores, textos e animações da UI do FaceTec

Solução de problemas

Hierarquia de erros e dicas de diagnóstico