WebViewCompat.navigate é uma alternativa aprimorada para
WebView.loadUrl que oferece controle refinado sobre o carregamento de páginas da Web,
o gerenciamento do histórico e o rastreamento do ciclo de vida de navegação em WebView.
Anteriormente, iniciar navegações de página usando loadUrl tinha limitações notáveis:
- Nenhuma substituição de entrada de histórico:não era possível substituir a entrada de histórico atual, o que impossibilitava a navegação para uma nova página sem adicionar uma entrada à pilha de retorno.
- Callbacks desacoplados:não havia um mecanismo direto para correlacionar uma chamada
loadUrlespecífica com eventos de callback subsequentes noWebViewClient. - Cabeçalhos extras não salvos:os cabeçalhos personalizados transmitidos para
loadUrlnão eram salvos como parte do estadoWebView, então eram perdidos ao restaurar o estado.
A API WebViewCompat.navigate resolve esses problemas ao introduzir os seguintes recursos:
- Substituição de entrada do histórico de navegação:permite substituir a página atual na pilha de histórico do
WebView. - Rastreamento de callback correlacionado: retorna um objeto
Navigationque serve como um identificador exclusivo em todas as fases de um ciclo de vida de navegação. - Suporte ao cabeçalho de estado salvo:cabeçalhos extras são salvos de forma confiável no pacote de estado
WebViewpara que possam ser reutilizados na restauração do estado.
Principais recursos e limitações
Antes de adotar WebViewCompat.navigate, considere as seguintes regras e restrições operacionais:
Segurança de linhas de execução:é necessário invocar
WebViewCompat.navigatena linha de execução da interface (principal).Cancelamento e precedência:as navegações em andamento não podem ser canceladas explicitamente. No entanto, iniciar uma nova chamada
navigateno mesmoWebViewsubstitui qualquer navegação ativa.Suporte ao esquema de URI:esquemas de URI padrão (como
https:ehttp:) e personalizados são aceitos. O esquemajavascript:não é aceito.Limite de tamanho do URL:o comprimento máximo da string de URL aceita é de 2 MB.
Verificação de recursos: sempre verifique a disponibilidade de recursos usando
WebViewFeature.isFeatureSupportedantes de invocar a API para manter a compatibilidade entre diferentes versões do APK do WebView.
Iniciar a navegação e rastrear o ciclo de vida
Para configurar a navegação e rastrear o ciclo de vida dela, faça o seguinte:
- Registre uma
NavigationListenerimplementação usandoWebViewCompat.addNavigationListenerdurante a configuração doWebViewpara receber callbacks estruturados do ciclo de vida. Registre o listener uma vez (em vez de em cada chamada de navegação) para evitar vazamentos de memória e execuções de callback duplicadas. - Construa uma
NavigationParametersinstância usandoNavigationParameters.Builderpara especificar comportamentos opcionais, como substituição de histórico ou cabeçalhos HTTP personalizados. - Chame
WebViewCompat.navigate, transmitindo a instânciaWebView, o URL de destino e os parâmetros.
WebViewCompat.navigate retorna um objeto Navigation que identifica exclusivamente
a solicitação. Nos seus NavigationListener callbacks, compare
esse objeto com o parâmetro Navigation recebido para rastrear essa navegação específica.
Exemplo de implementação
O exemplo a seguir demonstra como configurar parâmetros de navegação, invocar WebViewCompat.navigate e detectar eventos de ciclo de vida de navegação:
Kotlin
class WebNavigationManager(private val webView: WebView) {
// Track the navigation instance returned by the API
private var currentNavigation: Navigation? = null
init {
// 1. Define listener to observe navigation lifecycle events
val listener = object : NavigationListener {
override fun onNavigationStarted(navigation: Navigation) {
if (navigation == currentNavigation) {
// Navigation started
}
}
override fun onNavigationRedirected(navigation: Navigation) {
if (navigation == currentNavigation) {
// Navigation encountered a redirect
}
}
override fun onNavigationCompleted(navigation: Navigation) {
if (navigation == currentNavigation) {
if (navigation.didCommit()) {
// Navigation committed successfully
} else if (navigation.didCommitErrorPage()) {
// Navigation committed an error page
val statusCode = navigation.statusCode
val error = navigation.webResourceError
}
}
}
override fun onFirstContentfulPaintMillis(page: Page, durationMillis: Long) {
// Match page with current navigation
if (page == currentNavigation?.page) {
// Page rendering started (First Contentful Paint achieved)
}
}
}
// 2. Register listener on the main thread
WebViewCompat.addNavigationListener(webView, listener)
}
@UiThread
fun navigateToPage(url: String) {
// Check feature availability
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
// Fall back to standard loadUrl if navigate API is unavailable
webView.loadUrl(url)
return
}
// 3. Configure navigation parameters
val params = NavigationParameters.Builder()
.setShouldReplaceCurrentEntry(true)
.addAdditionalHeaders(
mapOf("X-Test-Navigate-Header" to "TestValue")
)
.build()
// 4. Initiate navigation on the UI thread
currentNavigation = WebViewCompat.navigate(webView, url, params)
}
}
Java
public class WebNavigationManager {
private Navigation mCurrentNavigation;
private final WebView mWebView;
public WebNavigationManager(@NonNull WebView webView) {
mWebView = webView;
setupListener();
}
private void setupListener() {
// 1. Define listener to observe navigation lifecycle events
NavigationListener listener = new NavigationListener() {
@Override
public void onNavigationStarted(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
// Navigation started
}
}
@Override
public void onNavigationRedirected(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
// Navigation encountered a redirect
}
}
@Override
public void onNavigationCompleted(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
if (navigation.didCommit()) {
// Navigation committed successfully
} else if (navigation.didCommitErrorPage()) {
// Navigation committed an error page
int statusCode = navigation.getStatusCode();
WebResourceErrorCompat error = navigation.getWebResourceError();
}
}
}
@Override
public void onFirstContentfulPaintMillis(@NonNull Page page, long durationMillis) {
if (mCurrentNavigation != null && page.equals(mCurrentNavigation.getPage())) {
// Page rendering started (First Contentful Paint achieved)
}
}
};
// 2. Register listener on the main thread
WebViewCompat.addNavigationListener(mWebView, listener);
}
@UiThread
public void navigateToPage(@NonNull String url) {
// Check feature availability
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
// Fall back to standard loadUrl if navigate API is unavailable
mWebView.loadUrl(url);
return;
}
// 3. Configure navigation parameters
NavigationParameters params = new NavigationParameters.Builder()
.setShouldReplaceCurrentEntry(true)
.addAdditionalHeaders(Collections.singletonMap(
"X-Test-Navigate-Header", "TestValue"
))
.build();
// 4. Initiate navigation on the UI thread
mCurrentNavigation = WebViewCompat.navigate(mWebView, url, params);
}
}
Modos de falha e tratamento de erros
A API WebViewCompat.navigate oferece mecanismos distintos para lidar com erros de configuração e falhas de navegação em tempo de execução:
Exceções de argumento inválido
A transmissão de argumentos inválidos aciona uma IllegalArgumentException síncrona.
As causas comuns incluem o seguinte:
- Transmitir
nullpara parâmetros obrigatórios não nulos (webView,urlouparams). - Fornecer um esquema de URL não aceito, como
javascript:. - Transmitir chaves ou valores de cabeçalho HTTP malformados que não estão em conformidade com as especificações da RFC 2616.
Erros no processo de navegação
Se ocorrer uma falha durante a solicitação de rede ou o carregamento de página (como um código de status HTTP 404 status code, falha de resolução de DNS ou erro SSL), WebViewCompat.navigate ainda retornará um objeto Navigation válido.
Quando a navegação terminar, inspecione os seguintes métodos na Navigation
instância dentro do seu onNavigationCompleted callback para diagnosticar a
falha:
getStatusCode: retorna o código de status da resposta HTTP (por exemplo,404ou500).getWebResourceError: retorna um objetoWebResourceErrorCompatdetalhando erros de rede, como tempos limite de conexão ou falhas de pesquisa de host.didCommitErrorPage: indica se oWebViewconfirmou e exibiu uma página de erro para o usuário.didCommit: indica se a navegação foi confirmada com sucesso em uma página de destino sem ser interrompida.
Salvar o gerenciamento de pacotes de estado
Ao transmitir cabeçalhos extras com NavigationParameters, o WebView salva esses cabeçalhos no pacote de estado salvo para que possam ser reutilizados na restauração do estado. No entanto, grandes coleções de cabeçalhos podem aumentar substancialmente o tamanho do Bundle de estado salvo.
Se você precisar restringir o tamanho do pacote para evitar TransactionTooLargeException
durante as salvamentos de estado do Android, use WebViewCompat.saveState. Esse método permite definir um limite máximo de tamanho do pacote em bytes e, opcionalmente, excluir itens de histórico de encaminhamento:
Kotlin
// Save state with a maximum bundle size limit (for example, 64 KB)
val maxSizeBytes = 64 * 1024
val includeForwardState = false
val outState = Bundle()
WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState)
Java
// Save state with a maximum bundle size limit (for example, 64 KB)
int maxSizeBytes = 64 * 1024;
boolean includeForwardState = false;
Bundle outState = new Bundle();
WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState);
O pacote resultante permanece compatível com o método padrão
WebView.restoreState.
Recomendações de migração e implementação
Para garantir o desempenho e a estabilidade ideais ao navegar no WebView, siga estas recomendações:
Migrar de
loadUrlparanavigate: migre todas as chamadas legadasWebView.loadUrlparaWebViewCompat.navigate. Isso garante o gerenciamento uniforme do histórico e que os cabeçalhos sejam sempre salvos como parte do estado salvo.Sempre verifique o suporte a recursos:antes de invocar a API, confirme o suporte em tempo de execução com
WebViewFeature.isFeatureSupportedpara se proteger contra versões mais antigas do WebView.Correlacionar instâncias de navegação:use o objeto
Navigationretornado para diferenciar navegações simultâneas ou filtrar callbacks ao gerenciar várias instânciasWebView.Registre o listener uma vez durante a inicialização: como
WebViewCompat.addNavigationListeneradiciona um listener em vez de substituir um já existente, registre oNavigationListeneruma vez duranteWebViewconfiguração para evitar vazamentos de memória e execuções de callback duplicadas em navegações subsequentes.Monitore o tamanho do estado salvo:ao transmitir grandes payloads de cabeçalho, use
WebViewCompat.saveStatecom limites de tamanho explícitos para evitar salvar dados de estado excessivos.
Outros recursos
Para saber mais sobre recursos da Web incorporados e otimização de desempenho, consulte os seguintes guias:
- Simplificar a implementação do WebView com o Jetpack Webkit
- Carregamento especulativo no WebView
- Otimizar a inicialização do WebView
- Processar o encerramento do processo de renderização do WebView