> ## Documentation Index
> Fetch the complete documentation index at: https://legitimuz.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Usar em WebView (app nativo)

> Abra o fluxo de verificação dentro de uma WebView e libere a câmera, o microfone e a geolocalização que o fluxo usa.

Não existe SDK nativo para iOS ou Android hoje — quando existir, esta página aponta para ele. Até
lá, o caminho para um app nativo é abrir, dentro de uma WebView, a mesma página que você já usaria
num navegador: com o Web SDK montado via [npm ou CDN](/web-sdk/overview), ou com o
[iframe próprio](/web-sdk/iframe). Nada nessa página muda por rodar numa WebView; o que muda é a
permissão que o seu app precisa conceder para a câmera, o microfone e a geolocalização funcionarem
dentro dela.

Ao final deste guia, a página abre dentro da WebView do seu app e a captura de documento, a prova de
vida e a coleta de geolocalização têm acesso ao que cada uma precisa.

## Por que a permissão não vem sozinha

Um navegador pede câmera, microfone e localização ao usuário quando a página chama `getUserMedia` ou
`navigator.geolocation`. Uma WebView embutida no seu app não pede: por padrão, ela nega em silêncio,
mesmo a página declarando a permissão corretamente — o que o Web SDK já faz no iframe que ele cria
(`allow="camera; microphone; geolocation; fullscreen"`, ver
[segurança](/web-sdk/security#o-que-o-sdk-impõe-no-iframe)). Sem o passo nativo abaixo, a captura e a
coleta de localização falham sem nenhum erro que a sua página consiga tratar.

## iOS — WKWebView

Declare os três textos de uso no `Info.plist` e implemente o delegado que autoriza câmera e
microfone:

```xml Info.plist theme={null}
<key>NSCameraUsageDescription</key>
<string>Usamos a câmera para capturar o seu documento e a sua selfie na verificação.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Usamos o microfone durante a prova de vida.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Usamos a sua localização para checar a origem da verificação.</string>
```

```swift theme={null}
webView.uiDelegate = self

extension VerificationViewController: WKUIDelegate {
  func webView(
    _ webView: WKWebView,
    requestMediaCapturePermissionFor origin: WKSecurityOrigin,
    initiatedByFrame frame: WKFrameInfo,
    type: WKMediaCaptureType,
    decisionHandler: @escaping (WKPermissionDecision) -> Void
  ) {
    decisionHandler(.grant)
  }
}
```

`requestMediaCapturePermissionFor` existe a partir do iOS 15 e cobre câmera e microfone. Sem o
delegado, a `WKWebView` recusa a concessão por padrão, mesmo com as chaves do `Info.plist`
presentes. `getUserMedia` em si só funciona em `WKWebView` de app de terceiro a partir do iOS 14.3;
abaixo disso a API não existe na página.

<Warning>
  Geolocalização não passa por delegado nenhum: a `WKWebView` não tem um método equivalente ao
  `requestMediaCapturePermissionFor` para `navigator.geolocation` hoje. Quem pede a autorização de
  localização ao sistema é o próprio WebKit — seu app não chama nada —, mas só faz isso com a chave
  `NSLocationWhenInUseUsageDescription` presente no `Info.plist`. Sem ela, o pedido nunca é feito e a
  página trava esperando uma posição que nunca chega, sem erro nenhum. Passe um `timeout` explícito
  em `getCurrentPosition`/`watchPosition` para não depender de detectar isso pelo travamento.
</Warning>

## Android — WebView

Declare as permissões no `AndroidManifest.xml`, peça a permissão em tempo de execução ao usuário
(Android 6.0+ exige isso independentemente da WebView) e conceda no `WebChromeClient`. Câmera e
microfone passam por `onPermissionRequest`; geolocalização é um método separado,
`onGeolocationPermissionsShowPrompt`, e precisa da própria configuração ligada no `WebSettings`:

```xml AndroidManifest.xml theme={null}
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
```

```kotlin theme={null}
webView.settings.javaScriptEnabled = true
webView.settings.setGeolocationEnabled(true)

webView.webChromeClient = object : WebChromeClient() {
  override fun onPermissionRequest(request: PermissionRequest) {
    request.grant(request.resources)
  }

  override fun onGeolocationPermissionsShowPrompt(
    origin: String?,
    callback: GeolocationPermissions.Callback?,
  ) {
    callback?.invoke(origin, true, false)
  }
}
```

Conceder aqui sem a permissão de runtime concedida ao app não libera nada: são duas camadas
separadas, e as duas precisam estar de acordo. E sem `setGeolocationEnabled(true)`,
`onGeolocationPermissionsShowPrompt` nunca dispara.

## Framework híbrido (React Native, Flutter e afins)

O mecanismo por baixo é o mesmo dos dois itens acima — o wrapper só decide como ele expõe isso.
Confira na documentação da versão do wrapper que você usa como conceder a permissão de mídia da
WebView nos dois sistemas; nem toda versão cobre iOS e Android da mesma forma.

No iOS, `getUserMedia` não funciona quando a página é servida por um esquema de URL customizado em
vez de `https://` ou `http://localhost` — é limitação da própria `WKWebView`, não do wrapper.
Confirme qual esquema a versão do seu wrapper usa antes de depurar a permissão.

<Accordion title="O que acontece se eu não implementar o passo nativo">
  A falha muda por plataforma e por capacidade, e vale saber qual é qual antes de abrir um chamado:

  * **Android, câmera sem `onPermissionRequest`**: erro imediato (`NotAllowedError`) — o default do
    `WebChromeClient` é negar.
  * **Android, geolocalização sem `onGeolocationPermissionsShowPrompt`**: nenhum erro. O callback
    nunca é chamado, e a chamada trava até o `timeout` que a página passar — ou para sempre, se ela
    não passar nenhum.
  * **iOS, câmera sem o delegado**: a `WKWebView` mostra o prompt do próprio sistema e funciona sem
    código nenhum, contanto que a chave do `Info.plist` esteja presente.
  * **iOS, geolocalização sem a chave do `Info.plist`**: o mesmo travamento silencioso do Android,
    por um motivo diferente (veja o aviso acima).

  Nas duas plataformas, "passo nativo ausente" e "titular recusou a permissão" chegam à página como
  o mesmo erro na maioria dos casos. Confirme o lado nativo antes de tratar a ausência de coleta como
  recusa do titular.
</Accordion>

<Card title="Iframe próprio" icon="app-window" href="/web-sdk/iframe">
  Se a página que a WebView abre não carrega o Web SDK, veja o que muda no tratamento de eventos.
</Card>
