> ## Documentation Index
> Fetch the complete documentation index at: https://docs-platform.services-valid.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Solução de problemas

> Hierarquia de erros e diagnóstico do LivenessFacetecSDK v10 no iOS

Esta página lista os erros emitidos pelo `LivenessFacetecSDK` para iOS, problemas comuns de build e dicas de diagnóstico.

## Erros de inicialização — `LivenessFacetecSDKInitError`

Lançados por `LivenessFacetecSDKClient.shared.initialize(config:)`:

```swift theme={"theme":"catppuccin-latte"}
public enum LivenessFacetecSDKInitError: Error, LocalizedError {
    case facetecInitializationFailed(String)
    case alreadyInitialized
}
```

| Erro                                  | Quando acontece                                                                                                                                                 | Ação recomendada                                                                                                                      |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `alreadyInitialized`                  | `initialize()` foi chamado enquanto o SDK já estava inicializado                                                                                                | Verifique `LivenessFacetecSDKClient.shared.isInitialized` antes de chamar. Para reinicializar (ex.: logout), chame `stop()` primeiro. |
| `facetecInitializationFailed(String)` | A inicialização falhou — cobre tanto uma rejeição do FaceTec (rejeição pelo servidor ou requisição abortada) quanto uma falha interna de provisionamento do SDK | A mensagem associada é **sempre genérica** e não distingue as duas causas. Se acontecer em todo launch, acione a equipe da Valid.     |

<Info>
  O tipo conforma `LocalizedError` — `error.localizedDescription` devolve uma mensagem legível.
</Info>

## Erros de fluxo — `LivenessFacetecSDKError`

Emitidos como `.error(LivenessFacetecSDKError)` pelo `AsyncStream` de `startLivenessCheck`:

```swift theme={"theme":"catppuccin-latte"}
public enum LivenessFacetecSDKError: Error, LocalizedError {
    case captureError(String)
    case submitError(String)
    case networkError(String)
    case sessionNotCompleted(status: ClientStatus, message: String)
    case unknown(String)
}
```

| Erro                                   | Quando acontece                                                                                                                                   | Ação recomendada                                                                                                  |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `sessionNotCompleted(status:message:)` | A sessão FaceTec terminou com status diferente de `.sessionCompleted` — cancelamento pelo usuário, lockout, erro de câmera, permissão negada etc. | Use o `status` para decidir a ação e o `message` como texto pronto para exibição. Veja a tabela de status abaixo. |
| `captureError(String)`                 | Erro interno durante a captura FaceTec                                                                                                            | Apresente UI de "tentar novamente". A `String` associada contém o motivo.                                         |
| `unknown(String)`                      | `startLivenessCheck`/`getSessionData` chamado sem `initialize()` bem-sucedido, ou erro inesperado                                                 | Verifique `isInitialized` antes de iniciar o fluxo. Se persistir, reporte a mensagem à equipe da Valid.           |
| `submitError(String)`                  | **Reservado** — nenhum caminho atual do SDK emite este caso                                                                                       | Mantido por estabilidade do enum. Trate no `switch` para exaustividade.                                           |
| `networkError(String)`                 | **Reservado** — nenhum caminho atual do SDK emite este caso                                                                                       | Mantido por estabilidade do enum. Trate no `switch` para exaustividade.                                           |

<Info>
  Não existem mais os casos `cancelled` nem `sessionError` da v9: o cancelamento do usuário agora chega como `.sessionNotCompleted`, decidido inteiramente pelo status local da FaceTec — nunca por uma chamada de rede. Erros de criação de sessão ocorrem antes de `startLivenessCheck` e são tratados pelo consumidor.
</Info>

### Status possíveis em `sessionNotCompleted`

O `ClientStatus` espelha o vocabulário de status compartilhado com a Web e declara **13 valores**, mas o iOS produz apenas os **8** abaixo — 7 aqui, mais `.sessionCompleted`, que nunca chega em `sessionNotCompleted` por definição:

| Status                     | Situação                                                  | Ação recomendada                                                                                |
| -------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `.userCancelledFaceScan`   | Usuário fechou a UI antes de completar os scans de rosto  | Retorno silencioso para a tela anterior; geralmente não é erro de UX.                           |
| `.userCancelledIdScan`     | Usuário cancelou antes de completar os scans de documento | Mesmo tratamento do caso anterior.                                                              |
| `.lockedOut`               | Limite de tentativas da sessão atingido                   | Não reabra a captura imediatamente. Informe o usuário e crie uma sessão nova após um intervalo. |
| `.cameraError`             | A câmera selecionada não está ativa                       | Oriente o usuário a fechar outros apps que usem a câmera e ofereça nova tentativa.              |
| `.cameraPermissionsDenied` | Permissão de câmera não concedida ou negada anteriormente | Direcione o usuário às configurações do app.                                                    |
| `.requestAborted`          | A aplicação abortou a requisição de sessão                | Verifique se a sessão criada no backend é válida e não expirou.                                 |
| `.unknownInternalError`    | Erro interno inesperado                                   | Apresente UI de "tentar novamente"; registre o `sessionId` se persistir.                        |

<Info>
  Os 5 casos restantes (`.rejectedByServer`, `.deviceNotSupported`, `.resourcesCouldNotBeLoadedOnLaser`, `.getUserMediaRemoteHttpNotSupported`, `.iframeNotAllowedWithoutPermission`) **nunca são emitidos no iOS** — pertencem ao vocabulário da Web. Ainda assim, o compilador os exige num `switch` exaustivo sobre `ClientStatus`; trate-os com um `default`.
</Info>

### Exemplo de tratamento

```swift theme={"theme":"catppuccin-latte"}
import LivenessFacetecSDK

func tratarErro(_ error: LivenessFacetecSDKError) {
    switch error {
    case .sessionNotCompleted(let status, let message):
        switch status {
        case .userCancelledFaceScan, .userCancelledIdScan:
            return // usuário desistiu — sem mensagem de erro
        case .cameraPermissionsDenied:
            abrirConfiguracoesDoApp()
        case .lockedOut:
            mostrarAlerta("Limite de tentativas atingido. Tente novamente mais tarde.")
        default:
            mostrarAlerta(message)
        }

    case .captureError(let detalhe):
        mostrarAlerta("A captura falhou: \(detalhe)")

    case .unknown(let detalhe):
        mostrarAlerta("Erro inesperado: \(detalhe)")

    case .submitError, .networkError:
        // Casos reservados — não emitidos pelo SDK atualmente
        mostrarAlerta(error.localizedDescription)
    }
}
```

## Problemas comuns de build

### Crash em runtime ao iniciar a captura

O `Info.plist` não declara `NSCameraUsageDescription`. O iOS termina o processo assim que o SDK tenta acessar a câmera.

Adicione:

```xml theme={"theme":"catppuccin-latte"}
<key>NSCameraUsageDescription</key>
<string>Esta permissão é necessária para verificação de identidade por biometria facial.</string>
```

### Crash no device com erro de code signing

A build phase de re-assinatura está ausente, mal posicionada ou desatualizada. Confirme que ela aponta para o `sign-nested-frameworks.sh` **entregue com o artefato atual** e roda depois do "Embed Frameworks" — veja [Instalação](/plataforma/liveness/facetec/v10/sdk/ios/instalacao#instalacao).

### `a sealed resource is missing or invalid` / crash com `EXC_BREAKPOINT` durante a sessão

O selo do `LivenessFacetecSDK.framework` está inconsistente. Isso acontece quando a build phase assina os frameworks aninhados **sem re-assinar o container** — o caso típico é uma cópia antiga do script colada dentro da build phase.

Substitua o conteúdo da fase pela chamada ao arquivo entregue pela Valid:

```bash theme={"theme":"catppuccin-latte"}
"${SRCROOT}/Scripts/sign-nested-frameworks.sh"
```

O script atual já cobre os dois passos e falha a build se o selo ficar inválido, em vez de deixar o problema aparecer só no device.

### `dyld: Library not loaded: @rpath/ShieldPtr.framework/ShieldPtr`

O XCFramework não foi embutido com **Embed & Sign**, ou a build phase de re-assinatura está ausente. Confira os passos de instalação.

### Erro de link `library not found for -lLivenessFacetecSDK`

O XCFramework não está sendo embarcado no target. Cheque em **General → Frameworks, Libraries, and Embedded Content** que o pacote está listado e marcado como **Embed & Sign**.

### Erro de deployment target

```text theme={"theme":"catppuccin-latte"}
'LivenessFacetecSDK' requires iOS 14.0 or later
```

Garanta **iOS Deployment Target ≥ 14.0** no projeto e no target.

### `alreadyInitialized` em runtime

`initialize()` foi chamado enquanto o SDK já estava inicializado. Verifique `LivenessFacetecSDKClient.shared.isInitialized` antes de chamar. Para reinicializar, chame `stop()` primeiro.

### `facetecInitializationFailed` em todo launch

Não é um problema de configuração do app consumidor: a inicialização foi rejeitada ou o provisionamento interno do SDK falhou. A mensagem devolvida é genérica e não distingue as duas causas — acione a equipe da Valid informando o Bundle Identifier do app.

### `.unknown("SDK not initialized. Call initialize() first.")`

`startLivenessCheck` ou `getSessionData` foi chamado antes de `initialize()` completar com sucesso. Verifique `isInitialized` antes de iniciar o fluxo.

### `ssid` vazio em `getSessionData()`

**Não é um erro.** A coleta de perimeter security é best-effort e pode devolver `ssid` vazio. Siga o fluxo normalmente — o backend aceita `ssid` vazio.

### Loop `for await` não encerra após o resultado

O stream encerra sozinho depois de `.success` ou `.error`. Se o loop não termina, verifique se o `Task` que o envolve não está sendo cancelado prematuramente.

## Limitação do simulador

<Warning>
  O FaceTec SDK **não suporta execução real no simulador iOS**. Esta é uma limitação deliberada do vendor, presente também na versão 10.1.19.
</Warning>

**Causa técnica:** o XCFramework de produção fornecido pela FaceTec inclui, no slice de simulador (`ios-arm64_x86_64-simulator`), um **binário stub** — bem menor que a implementação real presente no slice `ios-arm64`. O stub compila e linka normalmente, mas nunca completa uma inicialização real de sessão.

O slice de simulador (fat binary `arm64 + x86_64`) existe **apenas para permitir que apps consumidores compilem e vinculem ao SDK** sem erros de build. O fluxo de liveness jamais é executado em simulador — qualquer tentativa falha por construção, não por bug.

**Testes** de fluxo completo de liveness devem ser realizados **obrigatoriamente em dispositivo físico**.

## Privacidade e App Store

O XCFramework já embute o seu próprio `PrivacyInfo.xcprivacy`, e o `ShieldPtr.framework` aninhado traz o dele. A Apple agrega os dois automaticamente ao relatório do seu app — mas **as declarações finais na App Store são responsabilidade do app consumidor**.

| Dado coletado                | Origem | Vinculado ao usuário? |
| ---------------------------- | ------ | --------------------- |
| Biometria (face scan)        | SDK    | Não                   |
| Dados de crash               | SDK    | Não                   |
| Localização aproximada       | Shield | **Sim**               |
| Identificador de dispositivo | Shield | **Sim**               |

<Warning>
  Os dois itens do Shield são as únicas declarações com **`Linked = true`** entre as dependências deste SDK. Reflita **localização aproximada** e **identificador de dispositivo** no seu relatório de nutrição de privacidade antes de submeter o app — omiti-los é motivo comum de rejeição na revisão da App Store.
</Warning>

## Verificação de saúde

Use este checklist quando o SDK não inicializar:

<Steps>
  <Step title="Confirme o XCFramework correto">
    Verifique se está usando `LivenessFacetecSDK-Release.xcframework` (não uma variante de desenvolvimento ou um build anterior).
  </Step>

  <Step title="Confirme conectividade">
    O dispositivo precisa alcançar os endpoints da Plataforma ID. Teste em uma rede sem proxy/firewall corporativo.
  </Step>

  <Step title="Valide os frameworks aninhados">
    Verifique se `LivenessFacetecSDK-Release.xcframework/ios-arm64/LivenessFacetecSDK.framework/Frameworks/` contém `FaceTecSDK.framework` e `ShieldPtr.framework`.
  </Step>

  <Step title="Confirme a build phase de re-assinatura">
    A fase precisa apontar para `sign-nested-frameworks.sh` e rodar **depois** do "Embed Frameworks". Sem ela, qualquer instalação em device físico crasha logo no `dlopen`.
  </Step>

  <Step title="Confirme `NSCameraUsageDescription`">
    A captura é abortada pelo iOS se essa chave não estiver no `Info.plist`.
  </Step>

  <Step title="Teste em dispositivo físico">
    O simulador nunca completa uma sessão real, por design do vendor.
  </Step>
</Steps>

## Próximos passos

<CardGroup cols={2}>
  <Card title="Implementação" icon="code" iconType="regular" href="/plataforma/liveness/facetec/v10/sdk/ios/implementacao">
    Volte para a referência de uso do SDK
  </Card>

  <Card title="Customização" icon="palette" iconType="regular" href="/plataforma/liveness/facetec/v10/sdk/ios/customizacao">
    Veja como personalizar a UI do FaceTec
  </Card>
</CardGroup>
