Integração Fortface SDK no seu app iOS
Como funciona?
Objetivo da nossa SDK é efetuar a captura ou upload da foto do documento e enviá-la para nossa API Fortface. Para isso, há uma UIViewController que atua de forma independente do seu app, iniciada por uma Engine no momento que for estabelecido e, após processamento, encerra automaticamente.
Nossa SDK não se comunica diretamente com a API Fortface, veja abaixo o fluxo de comunicação:

Abaixo, seguem as instruções de integração da nossa SDK, fluxo de processos para acessar corretamente nosso serviço e passo-a-passo de como construir uma Engine.
Instalação
Requisito
iOS: versão mínima suportada é 13.0
Instalação
Versões a partir da 1.8
1. Importar pasta via SPM local
Faça o download clicando no link a seguir e descompacte o arquivo: Fortface.xcframework-1.9.zip
- No seu projeto, vá em
Package Dependenciese clique no+no final da listagem de Packages. - Em seguida, irá abrir uma nova tela para adicionar pacotes. No canto direito inferior, clique em
+. - Na parte inferior da tela, clique em
Add locale selecione a pasta baixada anteriormente. - Selecione o target do seu projeto e clique em
Add Package. - A nova dependência deve aparece na lateral direita do seu Xcode na parte de Package Dependencies.
Versões anteriores a 1.8
1. Adicionar o arquivo ao seu projeto
Primeiramente é necessário adicionar o Fortface.framework ao seu projeto, faça o download clicando no link a seguir e descompacte o arquivo: Fortface.xcframework-1.9.zip.
Para incluir a dependência da Fortface SDK no seu app, basta adicionar a pasta sdk.framework no seu projeto.
Exemplo:
seu_projeto/Fortface.framework

Permissão
Para efetuar a captura da foto, nossa SDK precisa ter acesso à câmera do dispositivo. Por isso, é solicitada permissão já no primeiro acesso.
Seguem os passos:
- No Xcode, guia do navegador de projetos (à esquerda), clique no ícone do projeto (azul) para selecioná-lo;
- Na guia principal do projeto, na seção "TARGETS" (ALVOS), selecione seu aplicativo;
- Guia "Info" (Informações), seção "Custom iOS Target Properties" (Propriedades Personalizadas do Alvo iOS), na última Key (Chave) clique no sinal de adição (+) para acrescentar uma nova propriedade;
- Selecione "Privacy - Camera Usage Description" (Privacidade - Descrição do Uso da Câmera);
- No campo "Value" (Valor), insira uma mensagem explicando porquê o app precisa acessar câmera. Por exemplo: "É necessário autorizar acesso à câmera para capturar fotos e vídeos."
Exemplo:
Pré-inicialização
Antes de iniciar o processo de captura, é necessário estabelecer a integridade do dispositivo para garantir uma comunicação segura com a API Fortface. Sendo assim, é preciso:
- Importar nossa SDK no seu app;
- Instanciar
FortfaceSDK.
Estabelecer a integridade do dispositivo
Inicie a SDK e obtenha o deviceRequestInfo.
- Swift
import Fortface
let deviceRequestInfo = FortfaceSDK.start(isDebugMode: true)
print(deviceRequestInfo)
// ztdTVLuGyQegvUnEtwAzcHbK8RoA9CXTuNRpCi9YXcwlzWpzOff+iOvUMkdprLk1E3npSKmk868x4pdJELztvRwu0auBrQdVFTu4wUI8ne35blqq1fds0ZHkOx8pfZGD4SIIPEVTEg2+uXQ8k6lxg7xoSnGzIPQJBZJmQWyDECXKDlXt+AAzMGN4lIWB2uM3ncwQLHPGDcGx52EgXBt3yQV7xZrCdinlwlDb21GK1kjygkRixqCvcB3LudlD8bYKKZq1PO5+faL0gFp6cTWpU9Fqkf7l9kbMc/5n+RGE83QzcQuLBzphDmIX2EUsqIdKFk/eg8WqAA9iC9YX4271/gt6RXqy2oQVJ4cyqD6bpLcRZtk/kLcW1lbo1h4bWyTyjC3XXnRPZVComA51s3Ouzxm4IxKX/EaTMd88n/ABiuE2s2DDKKKYc+WbqrDJo1btFHuXDA+O66mjrNKP+VE/CgtOrWF6W4x2cnpTNBJALmX23tion0caYxzbYpC18i3U
No FortfaceSDK, será usado método start que possui 1 parâmetro e retorna 1 string:
- Parâmetro
isDebugMode: booleano que habilita/desabilita modo de depuração. Valor defaultfalse;- Use
truepara habilitar o modo de depuração; - Use
falseem produção, assim é verificado a integridade do dispositivo e, caso não seja adequado para transações, será lançada uma excepetion do tipoFortfaceExceptioncom a mensagem There is something wrong!.
- Use
- Retorno armazenado em
deviceRequestInfo: string usada para validar integridade do dispositivo conectado à nossa SDK. Uma nova é gerada cada vez que o método é chamado (no código acima está um exemplo).
Com deviceRequestInfo em mãos, agora é possível fazer uma chamada de handshake entre seu back-end e API Fortface.
handshakeé uma medida de segurança importante para estabelecer uma comunicação confiável entre seu back-end e a API Fortface, possibilitando verificar autenticidade do dispositivo, compartilhar informações sensíveis (chaves de criptografia e sessões) e estabelecer um canal seguro para troca de dados.
Com o sucesso do handshake, haverá a garantia de que o dispositivo está íntegro e seu app tem as informações necessárias para prosseguir.
Captura e upload de documentos
O tamanho máximo de um arquivo (PDF/Imagem) para upload é de 4MB.
Arquivos maiores serão rejeitados com o código de erro FileSizeTooBig.
Sabendo que a integridade do dispositivo foi estabelecida, vamos entender como iniciar a sessão e utilizar a interface IFortfaceEngine para realizar a captura.
Estabelecer a sessão do dispositivo
Implemente uma classe que extenda IFortfaceEngine.
- Swift
class Engine: IFortfaceEngine {
init(sessionId: String, sessionKey: String, previousDoc: DocumentTypeEnum, documentList: [DocumentTypeEnum], openPhotoGalery: Bool) {
// Para captura de documentos
FortfaceManagerSession.startDocSessionEngine(
engine: self,
sessionId: sessionId,
sessionKey: sessionKey,
documentTypes: documentList,
previousDocType: previousDoc,
orientationManager: FortfaceOrientationManager()
)
// Para upload de documentos
FortfaceManagerSession.startUploadDocSessionEngine(
engine: self,
sessionId: sessionId,
sessionKey: encryptKey,
documentTypes: documentTypes,
openPhotoGalery: openPhotoGalery,
previousDocType: previousDoc
)
}
func finishedSessionEngine(sessionEngineResult: SessionEngineResult) {
switch sessionEngineResult {
case .capture:
captured(data: sessionEngineResult.data ?? Data())
case .cancel:
canceled()
case .timeout:
timeout()
case .deniedCamera:
cameraNotAuthorized()
case .error:
handleErrorAction(sessionDetails: sessionEngineResult.sessionDetails ?? Data())
default: return
}
}
private func captured(data: Data) {
let sdkData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String]
// Aqui encerra o fluxo e esses são os dados para enviar à API Fortface
}
private func canceled() {
// Aqui a pessoa usuária cancelou a captura. Você deve seguir com seu fluxo de cancelamento
}
private func timeout() {
// Aqui a captura foi cancelada pois o tempo esgotou. Você deve seguir com fluxo de tempo limite esgotado
}
private func cameraNotAuthorized() {
// Aqui a permissão de câmera não foi concedida pelo usuário. Você deve seguir com fluxo de permissão de câmera
}
private func handleErrorAction(sessionDetails: Data) {
// Aqui recebemos um JSON com o tipo de erro que aconteceu.
}
}
Nesta classe, inicialize FortfaceManagerSession e seu método startDocSessionEngine que possui 5 ou 6 parâmetros:
engine: representa a sua classe Engine que implementa a interfaceIFortfaceEngineda nossa SDK. Isso será explicado logo abaixo, na sessão Criando um Engine.sessionId: id da sessão, gerado na API Fortface;sessionKey: chave de criptografia gerado na API Fortface;documentTypes: representa a lista de documentos aceitos.- Os documentos aceitos são do tipo
DocumentTypeEnume podem ser: RG_FRONT, CNH_FRONT, RG_BACK, CNH_BACK, UNDEFINED, DOC_NOT_FOUND, PASSPORT.
- Os documentos aceitos são do tipo
previousDocType: representa o tipo de documento capturado anteriormente. Quando se é capturado / feito upload de um documento na primeira vez, esse parâmetro deve ter valor nil. O valor desse parâmetro é obtido através do response do serviço de API Fortface apoós o envio da primeira face.openPhotoGalery: usado apenas no upload de documento. Recebe umBoolque indica se o upload de documentos será via galeria de fotos os galeria de arquivos.orientationManager: é a classe responsável por saber a orientação do dispositivo;getGeolocation: define se o SDK deve coletar coordenadas de localização para reforço antifraude. (opcional)
O método startDocSessionEngine, que atualmente recebe até seis parâmetros para a captura de documentos, será descontinuado. Esse método já está marcado como obsoleto (@Deprecated) e deixará de funcionar em futuras versões do SDK.
Os parâmetros previousDocType e documentTypes serão descontinuados nas próximas releases.
- Swift
class FortfaceOrientationManager: IFortfaceOrientationManager {
private func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
É necessário adicionar esta configuração no AppDelegate do aplicativo integrador para que o orientationManager consiga se adequar nos casos de rotacionamento de tela. Atualmente estamos aceitando apenas a orientação portrait em captura de documentos.
- Swift
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
(...)
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
}
Dados mockados para exemplo:
sessionId = "nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2k"
sessionKey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2k+o81Oiti4TDezZYD8Q\nzj2RjO5f/YQHGmC1v7CWC4AJpD9+FOXBBO1pImaSg1gb8kOobRFGWbVdiHm35+PF\nTJceH31r+jKnvfc1TshsQVGtYLm7x5E/GFcjpGx9LdSxiXC6cHdCJf3o02/lytBa\nu8NCoH9FpPjyKrdGdSRb2haviAuEV4N1UBd5uZIsacVqZj52i1z+I94gLVKBZ/UV\npaxjLPWWngmaxbyKE0sEbt9JGleiCb2P1kZA9sU4L4Po7WBNk0+QOsvW9QjvS1+6\ntcZwwIDll2LyUceiFgxF6GkuFcHlBZDDtzymDDC2IYrf9/FNBOPeV1JHXON8T6DY\nAwIDAQAB\n-----END PUBLIC KEY-----\n"
A string que representa a sessionKey contém caracteres especiais (como a quebra de linha \n) que devem ser preservados exatamente como recebidos da API Fortface. Tenha cuidado com manipulações acidentais que possam ocorrer em:
- Inputs de formulários
- Logs e sistemas de monitoramento
- Processamento de strings no seu backend
- Transferência entre serviços
- Armazenamento em bancos de dados
Qualquer alteração nesses caracteres pode fazer com que a validação da chave falhe. Certifique-se de que a chave seja passada para o SDK exatamente como recebida da API Fortface.
Para desenvolvimento local do frontend exclusivamente, você pode reutilizar uma mesma sessionKey válida como mock quantas vezes forem necessárias. A restrição de uso único só é aplicada no contexto do desenvolvimento do backend, quando a API Fortface valida a chave.
Entendendo o trecho de código:
initvai fazer a chamada paraFortfaceManagerSession.start;- A sessão é criada e a câmera é renderizada na tela para captura de documento da pessoa usuária;
- Obs: no caso de upload de documento é aberto a galeria de arquivos ou galeria de fotos.
- Os dados são criptografados e enviados junto com a foto capturada para API Fortface;
- O retorno ocorre na função
finishedSessionEngineque é callback; sessionEngineResulté o objeto que possui 3 propriedades:data,actionesessionDetails- Se
sessionEngineResult.actiontrouxer o valor decapturefoi porque o fluxo seguiu como esperado, tendo retornado os dados da captura / upload; datacontém dado criptografado e pode ser convertido em JSON para facilitar sua manipulação. As chaves são geradas pela SDK, enviadas ao seu back-end e então à API Fortface.
{
key: String,
data: String,
imgData: String
}
-
Se
sessionEngineResult.actiontrouxer o valor decancelfoi porque pessoa usuária cancelou a captura ao tocar no botão Voltar, dessa forma deve-se seguir fluxo de cancelamento;- É possível esconder botão Voltar e, por consequência, não ter
action cancel, mais detalhes no tópico Customização.
- É possível esconder botão Voltar e, por consequência, não ter
-
Se
sessionEngineResult.actiontrouxer o valor detimeoutsignifica que o tempo estabelecido para captura foi esgotado, dessa forma deve-se seguir fluxo de tempo limite esgotado.- Essa
actionrepresenta o tempo que a SDK fica aberta, realizando captura ou não. Quando esgotar, a SDK é encerrada e câmera fechada; - O tempo padrão é de 20 segundos:
- Caso deseje manter, não precisa fazer nada;
- Caso deseje alterar, basta customizar o valor em segundos, mais detalhes no tópico Customização.
- Essa
-
Se
sessionEngineResult.actiontrouxer o valor dedeniedCamerasignifica que o usuário não permitiu o acesso a câmera quando o alerta de permissão apareceu. Dessa forma deve-se seguir fluxo de permissão de câmera. -
Se
sessionEngineResult.actiontrouxer o valor deerrorsignifica que ocorreu algum erro durante a captura ou upload de documento. Dessa forma deve-se seguir fluxo de erro.- O tipo de erro é retornado no JSON
sessionDetailsque pode ser decodificado usando o modeloSessionDetailsModel. Hoje os erros recebidos podem ser:- sameFace: código retornado quando a captura de uma segunda face do documento é do mesmo tipo que a face anterior informada.
- documentNotFound: código retornado quando o arquivo selecionado(PDF/Imagem) não consegue de ser encontrado.
- fileSizeTooBig: código retornado quando o arquivo selecionado(PDF/Imagem) é maior que o limite permitido de 4MB.
- fileCorrupted: código retornado quando o arquivo selecionado(PDF/Imagem) esta corrompido.
- O tipo de erro é retornado no JSON
ATENÇÃO!!
O fluxo é feito para cada “face” do documento, ou seja, frente e verso. Cada um deve ser feito o fluxo completo, passando pelo Handshake e startDocSessionEngine. Para a captura da segunda face deve ser informada o tipo de documento (Face do documento) reconhecimento na primeira captura, essa informação esta disponivel no response da chamada de API do serviço Fortface. A propriedade do json de response que se refere ao tipo de documento é a propriedade type, que esta contida no objeto fortfaceSdk.
Exemplo de json de response da API de serviço Fortface para captura de documento:
{
"api":{
"timestamp":1741712439604,
"version":"v1.13"
},
"handshake":{
"sessionId":"187ffa8d-016d-c0962506f5ab",
"sessionKey":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2t6V+LTwyClMN/2Dy5W8\nrJKMAwP45QTq+8e3RcNowUqKEDrsjSkBDYugYCaEuLY66pP3ndm8MfenHxuxAqGC\n3NagAUr83+kJufsizuUJTYC2/1CXeox8U1j4S0Ewt/4rr9SIZCwBisiFiT0THt6QFjE\nmwWMYVT4RjRUK8LV6pF1HJvjFHI6oXF2KjjFwVqXur5LB7sj9f70ddcp3Fiv/3Tn\nVQIDAQAB\n-----END PUBLIC KEY-----\n"
},
"message":"",
"providers":{
"fortfaceSdk":{
"automatic":true,
"confidence":0.73,
"type":"CNH_FRONT"
},
"identify":{
"status":"PENDING"
},
"ocr":{
"status":"PENDING",
"type":"ocr"
}
},
"sdk":{
"brand":"APPLE",
"model":"IPHONE_14",
"platform":"IOS"
},
"title":""
}
Versionamento
Para saber qual versão da nossa SDK está sendo utilizada, basta chamar a função FortfaceSDK.getVersion() que retornará uma String com seu valor. Exemplo:
let sdkVersion = FortfaceSDK.getVersion()
print(sdkVersion)
// 1.5.2
Callback de cancelamento e timeout
Quando uma tentativa de captura do rosto do usuário não é completada com sucesso, por exemplo quando o usuário cancela a captura ou quando a captura não acontece durante o tempo determinado, é importante que o acontecimento deste evento seja enviado ao backend para termos corretas métricas de sucesso ou falhas das capturas.
Para permitir que tenhamos os dados da captura cancelada ou que sofreu timeout, nossa SDK possui callbacks na ação de cancelar captura e na ação de timeout de captura.
O SessionEngineResult recebido na função finishedSessionEngine é um objeto no formato Data() que possui 2 propriedades: data e action (ação realizada na SDK). Anteriormente, o campo data era somente preenchido ao finalizar a captura de face.
Como visto anteriormente no tópico Captura, o data contém dados criptografados e pode ser convertidos em JSON. Entretanto, diferentemente da captura, neste cenário após a conversão para JSON, teremos somente os seguintes campos:
{
key: String,
data: String
}
Lembrete: As chaves key e data são geradas pela SDK, enviadas ao seu back-end e então à API Fortface.
Exemplo de implementação
-
Identificamos na SDK que houve um cancelamento de captura.
-
Criamos o objeto criptografado.
-
Terminamos a SDK e enviamos o payload gerado e a ação realizada.
-
No app de implementação, dentro da classe que extende o
IFortfaceEngine, é detectado que houve uma ação.
- Swift
class Engine: IFortfaceEngine {
...
func finishedSessionEngine(sessionEngineResult: SessionEngineResult) {
switch sessionEngineResult {
case .capture:
captured(data: sessionEngineResult.data ?? Data())
// ao detectar a ação de cancelar, é chamada a função canceled
// que recebe a data gerada na SDK.
case .cancel:
canceled(data: sessionEngineResult.data ?? Data())
case .timeout:
timeout(data: sessionEngineResult.data ?? Data())
case .error:
handleErrorAction(sessionDetails: sessionEngineResult.sessionDetails ?? Data())
default: return
}
}
private func canceled(data: Data) {
// envio do payload de cancelamento para uma API de métricas
metricService(data: Data)
}
private func metricService(data: Data) {
// pegamos o objeto do tipo Data e serializamos em JSON
if let metricRequest = try? JSONSerialization.jsonObject(with: self.actionServiceData, options: [])
as? [String: String] {
// transforma em um objeto do tipo Metric
let request = getMetricRequest(sdkJsonDataRequest: metricRequest)
// chama a camada de Service, enviando o Metric para a API
serviceAPI.postSessionMetric(metricRequest: request){ response, error in }
}
}
private func getMetricRequest(sdkJsonDataRequest: [String: String]) -> Metric {
let sdkData = SdkData(
key: sdkJsonDataRequest["key"], data: sdkJsonDataRequest["data"], imgData: nil)
return Metric(sdkData: sdkData)
}
...
}
- Objeto Metric enviado para a API
- Swift
import Foundation
struct Metric: Codable {
let sdkData: SdkData?
}
- Objeto SdkData
- Swift
import Foundation
struct SdkData: Codable {
let key: String?
let data: String?
let imgData: String?
}
Resumo
- Verificiar requisitos mínimos, acrescentar pasta e autorizar acesso à câmera;
- Capturar
deviceRequestInfo; - Fazer
handshake; - Iniciar Engine;
- Receber dados no callback;
- Enviar para API Fortface;
- Receber resposta da API Fortface e seguir com sua regra de negócio.