Uso do SDK em WebView e iframe

O Fortface SDK Web funciona embarcado em iframe, em Android WebView e em iOS WKWebView — mas nesses cenários quem controla o ambiente é o app host, não o navegador. Três coisas passam a depender da sua configuração:

  1. Permissões — câmera e, no Android, os sinais passivos de movimento;
  2. Renderização — a aceleração de hardware, usada nas validações de segurança do device;
  3. Identidade do dispositivo — o User-Agent, que informa qual aparelho está capturando.

Em todos os cenários: HTTPS é obrigatório (secure context — getUserMedia e devicemotion não existem em HTTP). Veja o requisito em Integração via CDN e o erro FORTFACE_INSECURE_PROTOCOL.


Iframe (embed web)

Adicione o atributo allow no iframe que carrega o fluxo:

<iframe
src="https://SEU-FLUXO..."
allow="camera; microphone; accelerometer; gyroscope; magnetometer"
></iframe>
  • camera é obrigatório. Sem ele, um iframe cross-origin tem getUserMedia bloqueado por Permissions-Policy. Nesse cenário, o SDK pode retornar o erro cameraAccessPolicyRestricted.
  • accelerometer; gyroscope; magnetometer liberam a coleta passiva de movimento no Chromium (Android). Sem eles a captura funciona, mas os sinais de motion não são coletados.
  • Inclua microphone. O SDK não captura áudio, mas a contagem de dispositivos de áudio é um dos sinais das validações de segurança do device — sem essa permissão a enumeração fica incompleta.
  • Não use sandbox no iframe (atributo HTML do <iframe> que restringe o que o conteúdo embarcado pode fazer, incluindo o acesso à câmera). Se for inevitável, precisa no mínimo de sandbox="allow-scripts allow-same-origin" — e teste o fluxo completo antes de subir.
  • A página host não pode negar essas permissões no header Permissions-Policy da própria resposta HTTP.

Android WebView

Duas camadas: o app precisa ter a permissão de câmera, e a WebView precisa repassá-la à página.

AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />

Runtime: solicite Manifest.permission.CAMERA ao usuário antes de abrir o fluxo (a WebView não mostra prompt próprio — se o app não tiver a permissão, o grant abaixo falha silenciosamente).

Configuração da WebView:

webView.settings.apply {
javaScriptEnabled = true
domStorageEnabled = true // localStorage
mediaPlaybackRequiresUserGesture = false
}

webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
// Recomendado: validar request.origin contra o domínio do fluxo.
request.grant(request.resources) // inclui RESOURCE_VIDEO_CAPTURE
}
}
  • Sem o onPermissionRequest, o getUserMedia dentro da WebView é negado mesmo com o app tendo a permissão.
  • É importante garantir que mediaPlaybackRequiresUserGesture esteja definida como false. Por padrão, a maioria das implementações de WebView define essa configuração como true, o que impede a reprodução automática de vídeos sem interação do usuário. Essa restrição impacta a experiência com o Fortface SDK Web, pois impossibilita que a filmagem da câmera seja exibida automaticamente para auxiliar no posicionamento correto para a captura da biometria facial.
  • Não desabilite hardware acceleration na Activity/WebView: isso troca o renderer WebGL por software e distorce os sinais de GPU usados nas validações de segurança do device.
  • devicemotion (sensores) funciona na WebView sem permissão adicional do Android.

Vale destacar que, mesmo que sua aplicação não tenha sido desenvolvida especificamente em uma WebView, ela pode ser executada em webviews de terceiros, como os navegadores embutidos em aplicativos como Instagram ou Telegram. Nesses cenários, geralmente mais limitados e com a configuração padrão ativa (true), o Fortface SDK Web exibirá um botão para que o usuário inicie manualmente a câmera, garantindo o consentimento necessário para iniciar a transmissão de vídeo.

Botão para iniciar a câmera

Observação: Existem casos raros em que webviews de terceiros não persistem a permissão concedida pelo usuário para acesso à câmera através do Fortface SDK Web. Nessas situações, pode ocorrer de o diálogo solicitando permissão para uso da câmera ser exibido mais de uma vez durante a experiência, exigindo que o usuário autorize novamente o acesso.


iOS WKWebView

Requisito de plataforma: iOS 14.3+ (antes disso getUserMedia não existe em WKWebView). O Fortface SDK Web exige no mínimo iOS 15.4 — veja Compatibilidades e Requisitos.

Info.plist:

<key>NSCameraUsageDescription</key>
<string>Usamos a câmera para a verificação de identidade.</string>

Configuração:

let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true // preview inline, não fullscreen
config.mediaTypesRequiringUserActionForPlayback = []
let webView = WKWebView(frame: .zero, configuration: config)

Permissão de câmera (iOS 15+, recomendado): sem este delegate o WebKit mostra um prompt próprio a cada sessão, somado ao prompt do sistema. Implemente WKUIDelegate e auto-aprove para o domínio do fluxo:

@available(iOS 15.0, *)
func webView(_ webView: WKWebView,
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
type: WKMediaCaptureType,
decisionHandler: @escaping (WKPermissionDecision) -> Void) {
// Validar origin.host contra o domínio do fluxo antes de conceder.
decisionHandler(origin.host == "SEU-DOMINIO" ? .grant : .prompt)
}
  • Solicitar a permissão de câmera do sistema (AVCaptureDevice.requestAccess(for: .video)) antes de abrir o fluxo melhora a UX (um prompt só, no momento certo).
  • Sensores de movimento não são coletados no iOS por design (o SDK nunca chama DeviceMotionEvent.requestPermission() para não disparar a modal) — nenhuma configuração necessária.

User-Agent: apende, nunca substitua

Substituir o User-Agent apaga o modelo do aparelho

Se o seu app troca a string de User-Agent inteira por uma fixa, todos os seus usuários passam a se reportar como o mesmo aparelho. O modelo real deixa de chegar até nós, o que degrada a análise antifraude e dificulta o suporte a investigar problemas específicos de aparelho.

A UA padrão da WebView já traz o modelo real do aparelho:

Mozilla/5.0 (Linux; Android 15; moto g54 5G Build/…; wv) …

Quando o app substitui essa string, o modelo vira uma constante falsa, igual para todos os seus usuários. Quando o app apenda o próprio token ao final da UA padrão, o modelo continua correto e o app continua identificável — esse é sempre o caminho.

Como fazer

// Android WebView — CERTO: apende ao padrão
val settings = webView.settings
settings.userAgentString = "${settings.userAgentString} MeuApp/1.2.3"
// Android WebView — ERRADO: substitui a string inteira
settings.userAgentString =
"Mozilla/5.0 (Linux; Android 10; Pixel 4) Chrome/101.0.4951.64 MeuApp/1.2.3"
// React Native WebView — use applicationNameForUserAgent (apende).
// A prop `userAgent` substitui: não use.
<WebView applicationNameForUserAgent="MeuApp/1.2.3" />
// WKWebView — use applicationNameForUserAgent (apende).
// `webView.customUserAgent` substitui: não use.
webView.configuration.applicationNameForUserAgent = "MeuApp/1.2.3"

No Flutter (webview_flutter) não existe API de append: setUserAgent sempre substitui. Se precisar marcar o app, leia navigator.userAgent da WebView antes e concatene o seu token ao valor lido — nunca escreva uma string montada à mão.

Melhor ainda: não use o User-Agent para isso

Se o objetivo é só o seu backend saber que a chamada veio do app, prefira um header HTTP customizado ou um campo na inicialização do SDK. O User-Agent existe para o navegador descrever o aparelho; identidade de app não é responsabilidade dele. Assim o problema deixa de existir em vez de depender de acertar a concatenação.

Como conferir a sua integração

Rode isto no contexto da WebView (via evaluateJavascript, DevTools remoto ou uma página de teste):

console.log(navigator.userAgent);

Confira que o seu token está no final da string e que o restante dela é o da WebView do aparelho de teste. O sinal de problema é a UA trazer um modelo que não é o do aparelho em mãos — aí a sua WebView está substituindo a string.

Se a UA padrão não traz modelo

Alguns navegadores não expõem o modelo do aparelho na UA — é normal e não exige nada de você. Não tente "corrigir" isso escrevendo uma UA à mão: é exatamente o problema descrito acima.


Checklist

  • HTTPS no host e no fluxo.
  • allow="camera; microphone; …" no iframe, sem sandbox.
  • Permissão de câmera do app concedida antes de abrir o fluxo.
  • onPermissionRequest (Android) / WKUIDelegate (iOS) implementados.
  • mediaPlaybackRequiresUserGesture = false / mediaTypesRequiringUserActionForPlayback = [].
  • Hardware acceleration ligada.
  • User-Agent padrão preservado (token apendado, nunca substituído) — conferido com o snippet acima.