Um link ou window.open dentro de um WebView não abre uma nova aba — não faz nada, em silêncio. No Android o padrão é setSupportMultipleWindows(false), que ignora todo pedido de abrir nova janela; para funcionar a app precisa ativar múltiplas janelas e implementar onCreateWindow e onCloseWindow, e a maioria nunca faz. No iOS, o delegado createWebViewWithConfiguration do WKWebView retorna nil por padrão, então target=_blank é descartado em silêncio a menos que a app implemente WKUIDelegate — e quando fazem, costumam criar um segundo WKWebView cujo histórico de voltar e avançar está desconectado do primeiro. Um runtime próprio do host traz um único gerenciador de janelas que mapeia popups para abas no app ou para um encaminhamento externo coerente, mantém o histórico intacto e nunca deixa um link morrer em silêncio.

Android: novas janelas ignoradas por padrão

A documentação do Android é direta: por padrão o sistema ignora pedidos de abrir novas janelas, seja via JavaScript ou via atributo target. Para respeitar target=_blank a app deve chamar setSupportMultipleWindows(true) e sobrescrever onCreateWindow (e onCloseWindow para limpar). Falta a flag e onCreateWindow nunca é chamado — o toque não gera navegação, nem erro, nada. O resultado prático no ecossistema é uma longa cauda de links mortos de "abrir em nova aba" que funcionam num navegador real e somem no WebView.

iOS: o delegado que retorna nil

O WKWebView não tem um modelo de abas ou janelas embutido; quando a página pede um novo contexto de navegação, ele pergunta à app via WKUIDelegate.createWebViewWithConfiguration. A implementação padrão retorna nil, o que significa que target=_blank e window.open são descartados em silêncio. Os desenvolvedores precisam definir o uiDelegate e implementar o método; a solução comum recarrega o pedido na mesma view (perdendo a semântica de nova aba) ou cria um WKWebView totalmente novo — cujo histórico de voltar e avançar é independente do original, então o usuário fica preso sem volta.

O que se perde sem um gerenciador de janelas

  • Links mortos sem feedback. Toques target=_blank não fazem nada, então o usuário acha que a página quebrou.
  • Histórico quebrado. Um segundo WebView tem seu próprio histórico de voltar/avançar, desconectando o usuário de onde veio.
  • Sem política coerente de links externos. Alguns links deveriam ficar no app, outros ir para o navegador do sistema; um WebView de fábrica não tem regra.
  • Contexto de sessão perdido. Um popup que deveria herdar login ou carrinho inicia frio num contexto à parte.
  • Divergência silenciosa. O mesmo HTML abre uma aba real no Safari e não faz nada na view embutida.

A solução do runtime

Um runtime próprio do host traz um único gerenciador de janelas abaixo da página. Mapeia cada pedido de nova janela para um resultado previsível — uma aba no app que compartilha o histórico e a sessão, ou um encaminhamento externo claramente rotulado para o navegador do sistema — e nunca engole um link em silêncio. O autor da página escreve um target=_blank padrão, e o runtime decide, de forma coerente e por política, o que acontece a seguir, em ambas as plataformas.

DimensãoWebViewRuntime próprio do host
Nova janela por padrãoIgnorada (Android) / delegado nil (iOS)Mapeada para aba ou encaminhamento
Flag AndroidsetSupportMultipleWindows + onCreateWindowGerenciado pelo runtime
Caminho iOSWKUIDelegate.createWebViewWithConfigurationGerenciado pelo runtime
Histórico de navegaçãoQuebrado numa segunda viewCompartilhado, intacto
Política de links externosNenhuma, adivinhação por appCoerente, configurável
Links mortos em silêncioComunsNunca

Um navegador trata target=_blank como uma promessa: um contexto novo e alcançável. Um WebView de fábrica o trata como um pedido que é livre para ignorar. Um runtime restaura a promessa — um gerenciador de janelas, histórico intacto e um link que sempre vai a um lugar que o usuário consegue ver.

Fontes