Estamos revisando estes procedimentos. Pessoas técnicas podem encontrar ajustes em códigos de erro ou mapeamentos de payload; valide com os logs e o OpenAPI mais recente. Pessoas não técnicas podem continuar usando o passo a passo e acionar o time de suporte caso algo pareça diferente do descrito.
⚛️ Utilizando a WebView no React Native
Este documento fornece um guia completo para implementar a WebView de biometria em aplicações React Native.
Configuração Inicial
Instalando a Dependência
Adicione a dependência de WebView ao seu projeto usando Yarn:
yarn add react-native-webview
Ou usando npm:
npm install --save react-native-webview
Nota: Caso seu projeto utilize
react-native@0.59ou inferior, siga o item 2 da documentação oficial do react-native-webview para vínculo manual da dependência.
Implementação Básica da WebView
Configuração Inicial do Componente
import * as React from 'react';
import { WebView } from 'react-native-webview';
export default function WebViewScreen() {
const webViewRef = React.useRef<WebView>(null);
return (
<WebView
ref={webViewRef}
javaScriptEnabled
allowsInlineMediaPlayback
webviewDebuggingEnabled
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false}
injectedJavaScriptForMainFrameOnly={false}
mediaCapturePermissionGrantType='grantIfSameHostElsePrompt'
mediaPlaybackRequiresUserAction={false}
source={{ uri: `${URL}` }}
style={{ flex: 1 }}
/>
);
}
Explicação das Propriedades
- ref: Busca a referência de instância do componente
- javaScriptEnabled: Permite que o WebView execute código JavaScript incorporado nas páginas web
- mediaPlaybackRequiresUserAction: Oculta os controles de reprodução de mídia
- webviewDebuggingEnabled: Habilita o depurador da WebView em modo Debug
- mediaCapturePermissionGrantType='grantIfSameHostElsePrompt': Configura o gerenciamento de permissões de recursos
- allowsInlineMediaPlayback: Oculta os controles de reprodução de mídia (somente iOS)
- source: Objeto contendo a URL que será aberta no WebView
- injectedJavaScriptBeforeContentLoadedForMainFrameOnly: Define se o script injetado será carregado apenas no frame principal (false carrega em todos os frames)
- injectedJavaScriptForMainFrameOnly: Similar ao anterior, mas para scripts injetados após o carregamento
Injetando Código JavaScript
Configurando OnInit e Event Listeners
import * as React from 'react';
import { WebView } from 'react-native-webview';
export default function WebViewScreen() {
const webViewRef = React.useRef<WebView>(null);
const onPostMessage = React.useMemo(() => `
window.postMessage({
type: "OnInit",
detail: {
authorization: "${authorization}",
token: "${token}",
isOperador: ${isOperador},
theme: {
primaryColor: '${primaryColor}',
buttonTextColor: '${buttonTextColor}'
},
}
});
`, [])
const eventSubscription = React.useMemo(() => `
window.addEventListener('message', (e) => {
if (e?.data?.type !== 'OnInit') {
window.ReactNativeWebView.postMessage(JSON.stringify({ type: e.data.type, ...e.data.detail }));
}
}, false)
`, [])
return (
<WebView
ref={webViewRef}
javaScriptEnabled
allowsInlineMediaPlayback
webviewDebuggingEnabled
mediaCapturePermissionGrantType="grantIfSameHostElsePrompt"
mediaPlaybackRequiresUserAction={false}
source={{uri: `${URL}`}}
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false}
injectedJavaScriptForMainFrameOnly={false}
injectedJavaScriptBeforeContentLoaded={`${eventSubscription}`}
injectedJavaScript={`${onPostMessage}`}
style={{flex: 1, marginTop: paddingTop, marginBottom: paddingBottom}}
/>
);
}
Vinculando Eventos JavaScript ao App
Definindo Tipos TypeScript
type CameraDecisionApproved = {
decision: 'APPROVED';
} & {
jwt: string;
base64: string;
};
type CameraDecisionDenied = { decision: 'DENIED' };
type CameraDecisionClose = { decision: 'CLOSE' };
type CameraResponse =
| ({ type: 'OnFinished' } & (
| CameraDecisionApproved
| CameraDecisionDenied
| CameraDecisionClose
))
| ({ type: 'OnError' } & { code: number; message: string })
| { type: 'OnInit' };
Implementação Completa com Tratamento de Eventos
import * as React from 'react';
import { WebView } from 'react-native-webview';
export default function WebViewScreen() {
const webViewRef = React.useRef<WebView>(null);
const onPostMessage = React.useMemo(() => `
window.postMessage({
type: "OnInit",
detail: {
authorization: "${authorization}",
token: "${token}",
isOperador: ${isOperador},
theme: {
primaryColor: '${primaryColor}',
buttonTextColor: '${buttonTextColor}'
},
}
});
`, [])
const eventSubscription = React.useMemo(() => `
window.addEventListener('message', (e) => {
if (e?.data?.type !== 'OnInit') {
window.ReactNativeWebView.postMessage(JSON.stringify({ type: e.data.type, ...e.data.detail }));
}
}, false)
`, [])
const onMessage = React.useCallback(
(event: WebViewMessageEvent) => {
const response: CameraResponse = JSON.parse(event.nativeEvent.data);
if (response.type !== 'OnInit') {
if (response.type === 'OnFinished') {
if (response.decision === 'APPROVED' || response.decision === 'DENIED') {
// O que deve ser feito quando receber o evento APPROVED ou DENIED
} else if (response.decision === 'CLOSE') {
// O que deve ser feito quando receber o evento CLOSE
}
} else {
// O que deve ser feito quando receber o evento OnError
}
}
},
[]
);
return (
<WebView
ref={webViewRef}
javaScriptEnabled
allowsInlineMediaPlayback
webviewDebuggingEnabled
mediaCapturePermissionGrantType="grantIfSameHostElsePrompt"
mediaPlaybackRequiresUserAction={false}
source={{uri: `${URL}`}}
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false}
injectedJavaScriptForMainFrameOnly={false}
injectedJavaScriptBeforeContentLoaded={`${eventSubscription}`}
injectedJavaScript={`${onPostMessage}`}
onMessage={onMessage}
style={{flex: 1, marginTop: paddingTop, marginBottom: paddingBottom}}
/>
);
}
Tratamento de Eventos
Evento OnFinished
Este evento é disparado quando o processo de biometria é concluído. As possíveis decisões são:
- APPROVED: Biometria aprovada
- DENIED: Biometria negada
- CLOSE: Usuário fechou a WebView
Para os casos APPROVED e DENIED, o evento contém os campos jwt (imagem criptografada) e base64 (imagem em base64).
Evento OnError
Disparado quando ocorre um erro durante o processo. Contém:
- code: Código do erro
- message: Mensagem descritiva do erro
Injeção de JavaScript
A injeção de JavaScript ocorre em dois momentos:
- injectedJavaScriptBeforeContentLoaded: Para adicionar o listener de eventos antes do conteúdo ser carregado
- injectedJavaScript: Para disparar o evento
OnInitapós o carregamento completo
Também é possível injetar diretamente ao componente utilizando a prop injectJavascript.
Pontos Importantes
- Use
React.useMemopara otimizar os scripts injetados - Use
React.useCallbackpara otimizar o handler de mensagens - A propriedade
webviewDebuggingEnableddeve ser habilitada apenas em desenvolvimento - Configure adequadamente as permissões de mídia para permitir acesso à câmera
- Implemente tratamento de erros robusto no callback
onMessage - Os tokens
authorizationetokensão obrigatórios no eventoOnInit
Compatibilidade de Plataforma
- iOS e macOS: Suportam injeção de JavaScript em todos os frames (iframes)
- Android: A injeção ocorre apenas no frame principal quando as props
ForMainFrameOnlyestão comotrue(padrão)
Para garantir compatibilidade completa, defina ambas as props como false:
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={false}injectedJavaScriptForMainFrameOnly={false}