Um crash nativo aparece em um painel de crashes com um stack trace que você pode abrir. Uma falha de WebView aparece como uma tela em branco e um ticket de suporte dizendo «não abre no meu telefone». A diferença não é sorte —é estrutura. Uma tela web embutida falha dentro de um processo ao qual você não consegue anexar um depurador, em uma compilação onde a depuração está desligada, com um código que você não consegue ler. Essa é a caixa preta de depuração, e é onde os incidentes morrem em silêncio.
A depuração está desligada por padrão — em ambas as plataformas
No Android, um WebView não aceita uma conexão do Chrome DevTools a menos que o app chame explicitamente WebView.setWebContentsDebuggingEnabled(true). A documentação do Android recomenda envolver essa chamada para que a depuração seja ativada só em builds depuráveis, nunca em produção. O guia de segurança móvel da OWASP (MASTG-BEST-0008) vai além: desative a depuração de WebView em produção justamente para que um atacante com o dispositivo não escute nem modifique o que flui por ele. No iOS, a Apple mudou as regras no iOS 16.4 —WKWebView.isInspectable agora é false por padrão—, então nenhum WebView é alcançável pelo Web Inspector do Safari a menos que o app o ligue deliberadamente, o que ninguém envia em um build de release. A postura segura, correta e padrão é: em produção, não há DevTools nenhum.
O renderizador é um processo que você não vê
Mesmo quando você ativa a depuração, o conteúdo web não vive no processo do seu app. No Android, o WebView executa o conteúdo web em um processo renderizador isolado em sandbox (construído a partir do Chromium). O próprio guia de memória do Google observa que o profiler do Android Studio se anexa ao processo do seu app e reporta seus heaps Java e nativo —mas os megabytes consumidos pelo JavaScript, DOM e imagens decodificadas da página residem naquele processo renderizador e são invisíveis às ferramentas do lado do app. A solução oficial é ativar a depuração de WebView e ler o renderizador via chrome://inspect. Em outras palavras, a única janela para a coisa que quebrou é exatamente o interruptor que a segurança diz para manter desligado.
Sem breakpoints, sem source maps, sem reproduzir
Assim, quando o H5 de um comerciante se comporta mal só dentro do seu app, o engenheiro está preso. Os consoles leves na página (vConsole, Eruda) imprimem logs, mas não oferecem breakpoints, nem inspeção de DOM, nem análise de performance ou memória —e devem ser removidos antes do release, então estão ausentes exatamente quando você mais precisa. Um caso real no Stack Overflow captura a armadilha: um site iframado no WKWebView de um app iOS de terceiros tinha um bug que aparecia só ali, não se reproduzia em nenhum navegador, e o desenvolvedor do app não podia entregar um build de depuração. O conselho degenerou em «envie seus dados de depuração como requisições HTTP para seu servidor». Isso não é depurar; é adivinhar com passos extras. E como os pacotes de produção são minificados, mesmo o erro que você pega aponta para a linha 1, coluna 8473 de um arquivo sem source map.
A solução do runtime
Um runtime de propriedade do host substitui a impossível depuração em produção por uma superfície governada. O runtime pode enviar telemetria estruturada de erros e console (não só relatórios de crash) de cada mini-programa, anexar source maps por um canal interno controlado, e oferecer inspeção autorizada pelo host, por sessão e auditada que a plataforma —não cada comerciante— liga e audita. Como o comportamento do runtime é versionado e idêntico em todos os dispositivos, uma falha se reproduz deterministicamente em vez de depender de qual motor a renderizou. A caixa preta vira uma superfície na qual você realmente consegue olhar.
| Dimensão | WebView | Runtime de propriedade do host |
|---|---|---|
| DevTools em produção | Desligado por padrão; a segurança proíbe | Autorizado pelo host, por sessão, auditado |
| Visibilidade do renderizador | Processo isolado em sandbox; profiler cego | O runtime reporta o processo web explicitamente |
| Source maps | Perdidos em bundles minificados | Enviados por um canal controlado |
| Rota de reprodução | Dependente do dispositivo e do motor | Versionado, determinístico entre dispositivos |
| Quem controla a inspeção | Cada comerciante, ou ninguém | A plataforma, por mini-programa |
O fio condutor desta série é o controle. O monitoramento diz que algo quebrou; a depuração diz por quê —e em um WebView, o segundo passo é o que falta. Um runtime te dá o porquê, em cada programa, sem abrir mão da postura de segurança em produção. Para uma app de tráfego cujo catálogo é código de terceiros, a depuração reproduzível é a diferença entre um conserto de 10 minutos e uma caça aos fantasmas de duas semanas.
Fontes
- Android Developers: Depurar WebViews com Chrome DevTools — a depuração de WebView é desligada por padrão; ative só em builds de desenvolvimento, não em produção.
- OWASP MASTG-BEST-0008: Depuração desativada para WebViews — desative a depuração de WebView em produção para evitar escutas e modificações.
- Guia de depuração de WebView iOS: isInspectable é false por padrão desde o iOS 16.4 — desde o iOS 16.4, todo WKWebView é não inspecionável a menos que ativado explicitamente; afeta debug e release.
- Android Developers: WebView e memória — o renderizador roda em um processo isolado em sandbox que o profiler do app não vê; só a depuração de WebView o revela.
- Stack Overflow: depurar JS em um WKWebView de terceiros sem build de debug — um caso real onde o bug só aparece dentro do app e não se reproduz nem depura em produção.