O Android oferece 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
de forma mais eficaz, melhorando a estabilidade e a segurança do app.
API Version
A partir do Android 7.0 (nível 24 da API), os usuários podem escolher entre vários
pacotes diferentes para mostrar 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á mostrando conteúdo
da Web no seu app. Esse método é útil para analisar erros que ocorrem apenas
quando o app tenta exibir conteúdo da Web usando a implementação
de WebView
de um pacote específico.
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);
Serviço de Navegação segura do Google
Para oferecer aos usuários uma experiência de navegação mais segura, os objetos WebView
verificam os URLs usando a
Navegação segura do Google,
que permite que seu app mostre um aviso aos usuários quando eles tentarem acessar um
site possivelmente não seguro.
Embora o valor padrão de EnableSafeBrowsing
seja "true", há
casos em que é recomendável ativar a Navegação segura apenas condicionalmente ou
desativá-la. O Android 8.0 (nível 26 da API) e versões mais recentes oferece suporte ao uso de
setSafeBrowsingEnabled()
para ativar a Navegação segura para um objeto WebView
individual.
Se você quiser que todos os objetos WebView
desativem as verificações da 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>
Definir ações programáticas
Quando uma instância de WebView
tenta carregar uma página
classificada pelo Google como uma ameaça conhecida, o WebView
, por padrão,
mostra um intersticial que avisa os usuários sobre a ameaça. Essa tela oferece
aos usuários a opção de carregar o URL mesmo assim ou retornar a uma página anterior segura.
Se seu app for destinado ao Android 8.1 (API de nível 27) ou versões mais recentes, você poderá definir de maneira programática como o app responde a uma ameaça conhecida das seguintes maneiras:
- Você pode controlar se o aplicativo reporta as ameaças conhecidas para o Navegação segura.
- Você pode fazer com que o app execute automaticamente uma ação específica, como voltar à segurança, sempre que encontrar um URL classificado como uma ameaça conhecida.
Os snippets de código abaixo mostram como instruir as instâncias de
WebView
do app a sempre voltar a um estado seguro após encontrar uma ameaça
conhecida:
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!"); } } }); } }
Kotlin
class MyWebViewClient : WebViewClientCompat() { // Automatically go "back to safety" when attempting to load a website that // Google identifies 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 identifies 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 destinados ao Android 6.0 (nível 23 da API) e versões mais recentes, a API Geolocation só é compatível com origens seguras, como HTTPS. Qualquer solicitação para a API Geolocation em origens não seguras é automaticamente negada, sem invocar o método onGeolocationPermissionsShowPrompt()
correspondente.
Desativar a coleta de métricas
O WebView
pode fazer o upload de dados de diagnóstico anônimos para
o Google quando o usuário consente. Os dados são coletados por app
para cada app que instancia uma WebView
. É possível desativar esse
recurso criando a tag abaixo no elemento
<application>
do manifesto:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
Os dados só são enviados de um app se o usuário consentir e não desativar o app. Para mais informações sobre como desativar os relatórios de dados de diagnóstico, consulte Privacidade do usuário nos relatórios da WebView.
API Termination Handling
A API Rescisão Handling processa casos em que o processo do renderizador para um objeto
WebView
desaparece porque o sistema encerra o renderizador para reivindicar
a memória necessária ou porque o processo do renderizador falha. Ao usar essa API, você
permite que o app continue em execução, mesmo que o processo do renderizador desapare.
Se um renderizador falhar ao carregar uma página da Web específica, uma tentativa de
carregar essa mesma página novamente poderá fazer com que um novo objeto WebView
exponha o mesmo comportamento de falha de renderização.
O snippet de código a seguir ilustra como usar essa API em uma
Activity
:
Kotlin
inner class MyRendererTrackingWebViewClient : WebViewClient() { private var mWebView: WebView? = null override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean { if (!detail.didCrash()) { // Renderer is 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 crashes 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 handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // 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 is 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 crashes 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 handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false; } }
API Renderer Importance
Quando objetos WebView
operam no
modo multiprocesso, você tem certa flexibilidade na forma como o app processa
situações de falta de memória. Você pode usar a API Renderer Importance, apresentada no
Android 8.0, para definir uma política de prioridade para o renderizador atribuído a um objeto
WebView
específico. Especificamente, você pode querer que a parte principal do
app continue em execução quando um renderizador que exibe os objetos
WebView
do app for eliminado. Você pode fazer isso, por exemplo, se
espera não mostrar o objeto WebView
por muito tempo para que o
sistema possa reivindicar a memória que o renderizador estava usando.
O snippet de código abaixo mostra como atribuir uma prioridade ao processo do renderizador
associado aos objetos WebView
do seu app.
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
Nesse snippet específico, 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 estiver mais visível. Em outras
palavras, um argumento true
indica que seu app não se importa se
o sistema mantém o processo do renderizador ativo. Na verdade, esse nível de prioridade mais baixo
faz com que o processo do renderizador seja encerrado em situações de falta
de memória.
Para saber mais sobre como o sistema processa situações de pouca memória, consulte Processos e ciclo de vida do app.