O Android 4.4 (API de nível 19) introduz uma nova versão da WebView
com base no Chromium. Essa mudança faz upgrade do desempenho da WebView
e padroniza a compatibilidade com HTML5, CSS3 e JavaScript para que correspondam aos navegadores da Web mais recentes. Todos os apps que usam WebView
herdarão esses upgrades ao serem executados no Android 4.4 e versões posteriores.
Este documento descreve outras mudanças da WebView
que você precisa conhecer se for definir sua targetSdkVersion
para "19" ou posterior.
Observação: se a targetSdkVersion
estiver definida como "18" ou anterior, WebView
operará no modo quirks para evitar o máximo possível algumas das mudanças de comportamento descritas abaixo e ainda fornecer upgrades de desempenho e de padrões da Web para seu app.
Entretanto, lembre-se de que layouts de coluna única e estreita e níveis de zoom padrão não são compatíveis com o Android 4.4, e pode haver outras diferenças de comportamento que não foram identificadas. Por isso, teste o app no Android 4.4 ou versões posteriores, mesmo se você mantiver a targetSdkVersion
definida como "18" ou anterior.
Para ajudar você a resolver problemas durante a migração do app para a WebView
no Android 4.4, ative a depuração remota pelo Chrome no seu computador chamando setWebContentsDebuggingEnabled()
.
Esse novo recurso na WebView
permite que você inspecione e analise o conteúdo da Web, os scripts e a atividade de rede durante a execução em uma WebView
. Para saber mais, consulte Depuração remota no Android.
Mudanças do user agent
Se você exibir conteúdo na sua WebView
com base no user agent, lembre-se de que a string do user agent mudou um pouco e agora inclui a versão do Chrome:
Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
Se você precisa recuperar o user agent, mas não precisa armazená-lo para seu app ou não quer instanciar WebView
, use o método estático, getDefaultUserAgent()
. No entanto, se você pretende modificar a string do user agent na WebView
, é recomendável usar getUserAgentString()
.
Multithreading e bloqueio de linhas de execução
Se você chamar métodos na WebView
usando qualquer linha de execução que não a da IU do app, isso poderá causar resultados inesperados. Por exemplo, se seu app usa várias linhas de execução, você pode usar o método runOnUiThread()
para garantir que o código seja executado na linha de execução de IU:
Kotlin
runOnUiThread { // Code for WebView goes here }
Java
runOnUiThread(new Runnable() { @Override public void run() { // Code for WebView goes here } });
Além disso, nunca bloqueie a linha de execução de IU. Alguns apps podem cometer esse erro enquanto aguardam um callback do JavaScript. Por exemplo, não use um código como este:
Kotlin
// This code is BAD and will block the UI thread webView.loadUrl("javascript:fn()") while (result == null) { Thread.sleep(100) }
Java
// This code is BAD and will block the UI thread webView.loadUrl("javascript:fn()"); while(result == null) { Thread.sleep(100); }
Em vez disso, use um novo método, evaluateJavascript()
, para executar o JavaScript de forma assíncrona.
Como gerenciar URL personalizado
A nova WebView
aplica mais restrições ao solicitar recursos e resolver links que usam um esquema de URL personalizado. Por exemplo, se você implementar callbacks como shouldOverrideUrlLoading()
ou shouldInterceptRequest()
, a WebView
os invocará apenas para URLs válidos.
Se você estiver usando um esquema de URL personalizado ou um URL base e perceber que o app está recebendo menos chamadas desses callbacks ou falhando em carregar recursos no Android 4.4, verifique se as solicitações especificam URLs válidos em conformidade com o RFC 3986.
Por exemplo, a nova WebView
pode não chamar seu método shouldOverrideUrlLoading()
para links como este:
<a href="showProfile">Show Profile</a>
O resultado do clique do usuário nesse link pode variar:
- Se você carregou a página chamando
loadData()
ouloadDataWithBaseURL()
com um URL base inválido ou nulo, você não receberá o callbackshouldOverrideUrlLoading()
para esse tipo de link na página.Observação: quando você usa
loadDataWithBaseURL()
e o URL base é inválido ou definido como nulo, todos os links no conteúdo que você está carregando precisam ser absolutos. - Se você carregou a página chamando
loadUrl()
ou se forneceu um URL base válido comloadDataWithBaseURL()
, você receberá o callbackshouldOverrideUrlLoading()
para esse tipo de link na página, mas o URL que você receber será absoluto em relação à página atual. Por exemplo, o URL que você receber será"http://www.example.com/showProfile"
em vez de apenas"showProfile"
.
Em vez de usar uma string simples em um link, como mostrado acima, você pode usar um esquema personalizado como o seguinte:
<a href="example-app:showProfile">Show Profile</a>
Em seguida, você pode gerenciar esse URL no método shouldOverrideUrlLoading()
, desta forma:
Kotlin
// The URL scheme should be non-hierarchical (no trailing slashes) const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Java
// The URL scheme should be non-hierarchical (no trailing slashes) private static final String APP_SCHEME = "example-app:"; @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(APP_SCHEME)) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8"); respondToData(urlData); return true; } return false; }
Se não for possível mudar o HTML, você poderá usar loadDataWithBaseURL()
e definir um URL base que consista em um esquema personalizado e um host válido, como "example-app://<valid_host_name>/"
. Exemplo:
Kotlin
webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA, null, "UTF-8", null)
Java
webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA, null, "UTF-8", null);
O nome de host válido precisa estar de acordo com o RFC 3986, e é importante incluir a barra no final. Caso contrário, as solicitações da página carregada podem ser descartadas.
Mudanças na janela de visualização
A propriedade target-densitydpi da janela de visualização não é mais compatível
Anteriormente, a WebView
era compatível com uma propriedade da janela de visualização chamada target-densitydpi
para ajudar as páginas da Web a especificar a densidade desejada para a tela. Essa propriedade não é mais compatível, e você precisa migrar para o uso de soluções padrão com imagens e CSS, conforme discutido em IU Pixel-Perfect no modo WebView (link em inglês).
A janela de visualização aumenta o zoom quando está pequena
Anteriormente, se você definia a largura da janela de visualização como um valor menor ou igual a "320", ela era definida como "device-width", e se você definia a altura da janela de visualização como um valor menor ou igual à altura da WebView
, ela era definida como "device-height". No entanto, ao executar na nova WebView
, o valor de largura ou altura é respeitado, e a WebView
aumenta o zoom para preencher a largura da tela.
Várias tags da janela de visualização não são compatíveis
Anteriormente, se você incluía várias tags da janela de visualização em uma página da Web, a WebView
mesclava as propriedades de todas elas.
Na nova WebView
, somente a última janela de visualização é usada, e todas as outras são ignoradas.
O zoom padrão se tornou obsoleto
Os métodos getDefaultZoom()
e setDefaultZoom()
para receber e definir o nível de zoom inicial em uma página não são mais compatíveis, e você precisa definir a janela de visualização adequada na página da Web.
Atenção: essas APIs não são compatíveis com o Android 4.4 ou versões posteriores. Mesmo que a targetSdkVersion
esteja definida como "18" ou menos, essas APIs não terão efeito.
Para saber mais sobre como definir as propriedades da janela de visualização no HTML, leia IU Pixel-Perfect no modo WebView.
Se não for possível definir a largura da janela de visualização no HTML, chame setUseWideViewPort()
para garantir que a página receba uma janela de visualização maior. Exemplo:
Kotlin
webView.settings.apply { useWideViewPort = true loadWithOverviewMode = true }
Java
WebSettings settings = webView.getSettings(); settings.setUseWideViewPort(true); settings.setLoadWithOverviewMode(true);
Mudanças de estilo
A abreviação do CSS do segundo plano modifica o tamanho do segundo plano
O Chrome e outros navegadores se comportaram dessa forma por algum tempo, mas agora WebView
também modifica uma configuração de CSS para background-size
se você especificar o estilo background
. Por exemplo, o tamanho aqui será redefinido para um valor padrão:
.some-class { background-size: contain; background: url('images/image.png') no-repeat; }
A correção é simplesmente uma alternância entre as duas propriedades.
.some-class { background: url('images/image.png') no-repeat; background-size: contain; }
Os tamanhos estão em pixels CSS em vez de pixels na tela
Anteriormente, os parâmetros de tamanho, como window.outerWidth
e window.outerHeight
(links em inglês), retornavam um valor em pixels reais da tela.
Na nova WebView
, um valor com base em pixels CSS é retornado.
Tentar calcular o tamanho físico em pixels para elementos de dimensionamento ou outros cálculos não costuma ser recomendado. No entanto, se você tiver desativado o zoom, e a escala inicial for definida como 1.0, você poderá usar window.devicePixelRatio
para descobrir a escala e depois multiplicar o valor do pixel CSS por ela. Você também pode criar uma vinculação JavaScript para consultar o tamanho do pixel pela própria WebView
.
Para mais informações, consulte quirksmode.org (link em inglês).
NARROW_COLUMNS e SINGLE_COLUMN não são mais compatíveis
O valor NARROW_COLUMNS
para WebSettings.LayoutAlgorithm
não é compatível com a nova WebView
.
Atenção: essas APIs não são compatíveis com o Android 4.4 ou versões posteriores. Mesmo que a targetSdkVersion
esteja definida como "18" ou menos, essas APIs não terão efeito.
Você pode gerenciar essa mudança das seguintes maneiras:
- Mudar os estilos do aplicativo:
Se você tem controle do HTML e do CSS na página, mudar o design do seu conteúdo pode ser a abordagem mais confiável. Por exemplo, nas telas em que você cita licenças, recomendamos colar o texto dentro de uma tag
<pre>
, o que pode ser feito com os seguintes estilos:<pre style="word-wrap: break-word; white-space: pre-wrap;">
Isso pode ser particularmente útil se você não tiver definido as propriedades da janela de visualização para sua página.
- Usar o novo algoritmo de layout
TEXT_AUTOSIZING
:Se você usava colunas estreitas como uma maneira de tornar uma ampla gama de sites para computador mais legível em dispositivos móveis e não conseguiu mudar o conteúdo do HTML, o novo algoritmo
TEXT_AUTOSIZING
pode ser uma alternativa adequada aNARROW_COLUMNS
.
Além disso, o valor SINGLE_COLUMN
, que estava obsoleto, também não é compatível com a nova WebView
.
Como gerenciar eventos de toque no JavaScript
Se a página da Web estiver gerenciando diretamente os eventos de toque em uma WebView
, você também precisa estar gerenciando o evento touchcancel
(link em inglês). touchcancel
será chamado em algumas situações, o que pode causar problemas se ele não for recebido:
- Um elemento é tocado (ou seja,
touchstart
etouchmove
são chamados) e a página é rolada, fazendo com que umtouchcancel
seja acionado. - Um elemento é tocado (
touchstart
é chamado), masevent.preventDefault()
não é chamado, resultando em antecedência suficiente para quetouchcancel
seja acionado. Portanto,WebView
presume que você não quer consumir os eventos de toque.