O Android fornece várias APIs para ajudar você a gerenciar os objetos WebView
que exibem conteúdo da Web no seu app.
Esta página descreve como usar essas APIs para trabalhar com objetos WebView
com mais eficiência, melhorando a estabilidade e a segurança do app.
API Version
A partir do Android 7.0 (API de nível 24), os usuários podem escolher entre vários pacotes diferentes para exibir conteúdo da Web em um objeto WebView
. A biblioteca androidX webKit inclui o método
getCurrentWebViewPackage()
para buscar informações relacionadas ao pacote que está exibindo conteúdo da Web no seu app. Esse método é particularmente útil ao analisar erros que ocorrem apenas quando o app tenta exibir conteúdo da Web usando a implementação de um pacote específico da WebView
.
Para usar esse método, adicione a lógica mostrada no snippet de código a seguir:
Kotlin
val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext) Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")
Java
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext); Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
Observação: o método getCurrentWebViewPackage()
pode retornar como null
se o dispositivo tiver sido configurado incorretamente, não for compatível com o uso de WebView
(como um dispositivo com Wear OS) ou não tiver uma implementação WebView
atualizável, como no Android 4.4 (API de nível 19) e versões anteriores.
Serviço de Navegação segura do Google
Para oferecer uma experiência de navegação mais segura aos usuários, os objetos WebView
verificam URLs usando o serviço Navegação segura do Google, que permite que o app exiba um aviso aos usuários quando eles tentarem navegar para um site potencialmente inseguro.
Enquanto o valor padrão de EnableSafeBrowsing
for verdadeiro, haverá casos ocasionais em que você poderá querer ativar o "Navegação segura" apenas condicionalmente ou desativá-lo. O Android 8.0 (API de nível 26) e as versões posteriores são compatíveis com o uso de
setSafeBrowsingEnabled()
para alternar o "Navegação segura" para um objeto WebView
individual.
WebView
desativem as verificações do "Navegação segura", adicione o seguinte elemento <meta-data>
ao arquivo de manifesto do app:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
Como definir ações programáticas
Quando uma instância de WebView
tenta carregar uma página que foi classificada pelo Google como uma ameaça conhecida, a WebView
mostra, por padrão, um intersticial que avisa os usuários sobre a ameaça. Essa tela dá aos usuários a opção de carregar o URL mesmo assim ou de retornar à página segura anterior.
Se seu objetivo for o Android 8.1 (API de nível 27) ou versões posteriores, você pode definir programaticamente como seu app responde a uma ameaça conhecida:
- Você pode controlar se o aplicativo reporta as ameaças conhecidas para o "Navegação segura".
- Você pode fazer com que o app realize automaticamente uma ação específica, como voltar à segurança, sempre que encontrar um URL classificado como uma ameaça conhecida.
Observação: para conseguir a melhor proteção contra ameaças conhecidas, aguarde até inicializar o "Navegação segura" antes de invocar um método loadUrl()
do objeto WebView
.
Os snippets de código a seguir mostram como você pode instruir as instâncias de WebView
do app a sempre voltar à segurança depois de encontrar uma ameaça conhecida:
MyWebActivity.java
Kotlin
private lateinit var superSafeWebView: WebView private var safeBrowsingIsInitialized: Boolean = false // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) superSafeWebView = WebView(this) superSafeWebView.webViewClient = MyWebViewClient() safeBrowsingIsInitialized = false if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, ValueCallback<Boolean> { success -> safeBrowsingIsInitialized = true if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!") } }) } }
Java
private WebView superSafeWebView; private boolean safeBrowsingIsInitialized; // ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); superSafeWebView = new WebView(this); superSafeWebView.setWebViewClient(new MyWebViewClient()); safeBrowsingIsInitialized = false; if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, new ValueCallback<Boolean>() { @Override public void onReceiveValue(Boolean success) { safeBrowsingIsInitialized = true; if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!"); } } }); } }
MyWebViewClient.java
Kotlin
class MyWebViewClient : WebViewClientCompat() { // Automatically go "back to safety" when attempting to load a website that // Google has identified as a known threat. An instance of WebView calls // this method only after Safe Browsing is initialized, so there's no // conditional logic needed here. override fun onSafeBrowsingHit( view: WebView, request: WebResourceRequest, threatType: Int, callback: SafeBrowsingResponseCompat ) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true) Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show() } } }
Java
public class MyWebViewClient extends WebViewClientCompat { // Automatically go "back to safety" when attempting to load a website that // Google has identified as a known threat. An instance of WebView calls // this method only after Safe Browsing is initialized, so there's no // conditional logic needed here. @Override public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponseCompat callback) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true); Toast.makeText(view.getContext(), "Unsafe web page blocked.", Toast.LENGTH_LONG).show(); } } }
API HTML5 Geolocation
Para apps voltados ao Android 6.0 (API de nível 23) ou versões posteriores, a API Geolocation só é compatível com origens seguras, como o HTTPS. Qualquer solicitação para a API Geolocation em origens não seguras é automaticamente negada, sem invocar o método onGeolocationPermissionsShowPrompt()
correspondente.
Como desativar a coleta de métricas
A WebView
consegue fazer upload de dados de diagnóstico anônimos para o Google diante do consentimento do usuário. Os dados são coletados em cada app para cada aplicativo que instanciar uma WebView
. Você pode desativar esse recurso criando a seguinte tag no elemento <application>
do manifesto:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
O upload dos dados só será feito a partir de um app se o usuário consentir e se o app não tiver desativado a opção.
API Termination Handling
Essa API gerencia casos em que o processo do renderizador de um objeto WebView
desaparece, seja porque o sistema interrompeu o renderizador para reivindicar a memória necessária ou porque o processo do renderizador falhou. Ao usar essa API, você permite que seu app continue em execução, mesmo que o processo do renderizador tenha sido removido.
Atenção: se o app continuar em execução após o fim do processo do renderizador, a instância associada de WebView
não poderá ser reutilizada, independentemente da interrupção ou do travamento do processo do renderizador. Seu app precisa remover a instância da hierarquia de visualização e destruí-la para continuar a execução. Depois disso, o app precisa criar uma instância inteiramente nova de WebView
para continuar processando páginas da Web.
Se um renderizador travar ao carregar uma determinada página da Web, tentar carregar a mesma página novamente poderá fazer com que um novo objeto WebView
exiba o mesmo comportamento de falha de renderização.
O snippet de código a seguir ilustra como usar essa API:
Kotlin
inner class MyRendererTrackingWebViewClient : WebViewClient() { private var mWebView: WebView? = null override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean { if (!detail.didCrash()) { // Renderer was killed because the system ran out of memory. // The app can recover gracefully by creating a new WebView instance // in the foreground. Log.e("MY_APP_TAG", ("System killed the WebView rendering process " + "to reclaim memory. Recreating...")) mWebView?.also { webView -> val webViewContainer: ViewGroup = findViewById(R.id.my_web_view_container) webViewContainer.removeView(webView) webView.destroy() mWebView = null } // By this point, the instance variable "mWebView" is guaranteed // to be null, so it's safe to reinitialize it. return true // The app continues executing. } // Renderer crashed because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!") // In this example, the app itself crashes after detecting that the // renderer crashed. If you choose to handle the crash more gracefully // and allow your app to continue executing, you should 1) destroy the // current WebView instance, 2) specify logic for how the app can // continue executing, and 3) return "true" instead. return false } }
Java
public class MyRendererTrackingWebViewClient extends WebViewClient { private WebView mWebView; @Override public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { if (!detail.didCrash()) { // Renderer was killed because the system ran out of memory. // The app can recover gracefully by creating a new WebView instance // in the foreground. Log.e("MY_APP_TAG", "System killed the WebView rendering process " + "to reclaim memory. Recreating..."); if (mWebView != null) { ViewGroup webViewContainer = (ViewGroup) findViewById(R.id.my_web_view_container); webViewContainer.removeView(mWebView); mWebView.destroy(); mWebView = null; } // By this point, the instance variable "mWebView" is guaranteed // to be null, so it's safe to reinitialize it. return true; // The app continues executing. } // Renderer crashed because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!"); // In this example, the app itself crashes after detecting that the // renderer crashed. If you choose to handle the crash more gracefully // and allow your app to continue executing, you should 1) destroy the // current WebView instance, 2) specify logic for how the app can // continue executing, and 3) return "true" instead. return false; } }
API Renderer Importance
Agora que objetos WebView
operam no modo multiprocesso, você tem certa flexibilidade na forma como o app gerencia situações de falta de memória. Você pode usar a API Renderer Importance, introduzida no Android 8.0, para definir uma política de prioridade para o renderizador atribuído a um objeto WebView
. Especificamente, você pode querer que a parte principal do app continue em execução quando um renderizador que exibe os objetos WebView
dele for eliminado. Você pode fazer isso, por exemplo, se não mostrar o objeto WebView
por um longo período para que o sistema possa reivindicar a memória que o renderizador estava usando.
O snippet de código a seguir mostra como atribuir uma prioridade ao processo do renderizador associado aos objetos WebView
do app:
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
Nesse snippet, a prioridade do renderizador é a mesma que a prioridade padrão do app ou está vinculada a ela. O argumento true
diminui a prioridade do renderizador para RENDERER_PRIORITY_WAIVED
quando o objeto WebView
associado não está mais visível. Em outras palavras, um argumento true
indica que, para o app, não faz diferença se o sistema mantém o processo do renderizador ativo. Esse nível de prioridade menor torna provável que o processo do renderizador seja interrompido em situações de falta de memória.
Aviso: para manter a estabilidade do app, não mude a política de prioridade do renderizador para um objeto WebView
, a menos que você também use a API Termination Handle para especificar de que forma WebView
reage quando o renderizador associado desaparece.
Para saber mais sobre como o sistema gerencia situações de pouca memória, consulte Processos e ciclo de vida do app.