Gerenciar objetos WebView

O Android fornece várias APIs para ajudar você a gerenciar WebView objetos que exibem conteúdo da Web no seu app.

Esta página descreve como usar essas APIs para trabalhar com WebView objetos de forma mais eficaz, melhorando a estabilidade e a segurança do aplicativo.

API Version

A partir do Android 7.0 (API de nível 24), os usuários podem escolher entre várias pacotes diferentes para exibir conteúdo da Web em um objeto WebView. A classe AndroidX.webkit inclui o getCurrentWebViewPackage() para buscar informações relacionadas ao pacote que exibe dados da Web conteúdo no seu app. Esse método é útil ao analisar erros que ocorrem apenas quando o app tenta exibir conteúdo da Web usando o implementação de 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);

Serviço de Navegação segura do Google

Para oferecer aos usuários uma experiência de navegação mais segura, WebView verificam URLs usando Navegação segura do Google, que permite que o app mostre um aviso aos usuários quando eles tentarem navegar para uma site potencialmente perigoso.

Embora o valor padrão de EnableSafeBrowsing seja verdadeiro, não há são casos em que você só quer ativar a Navegação segura condicionalmente ou desativá-la. O Android 8.0 (nível 26 da API) e versões mais recentes oferecem suporte ao uso setSafeBrowsingEnabled() para ativar o recurso Navegação segura para um objeto WebView individual.

Se você quiser que todos os objetos WebView desativem o recurso Navegação segura da conta, adicione o seguinte elemento <meta-data> ao arquivo de manifesto:

<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 que está classificadas pelo Google como uma ameaça conhecida, o WebView, por padrão, mostra um intersticial que avisa os usuários sobre a ameaça conhecida. Essa tela mostra aos usuários a opção de carregar o URL mesmo assim ou de retornar à página anterior seguros.

Se você destinar ao Android 8.1 (API de nível 27) ou posterior, poderá definir de forma programática, como o app responde a uma ameaça conhecida das seguintes maneiras: maneiras:

  • É possível controlar se o app reporta as ameaças conhecidas para o Navegação.
  • É possível fazer com que o aplicativo execute automaticamente uma ação específica, como para voltar à segurança. Sempre que encontra um URL pode ser classificado como uma ameaça conhecida.
.

Os snippets de código a seguir mostram como instruir as instâncias de WebView para sempre voltar a um local seguro depois de encontrar um ameaça:

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 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 é compatível apenas com origens seguras, como HTTPS. Qualquer solicitação feita ao 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 consegue fazer o upload de dados de diagnóstico anônimos para o Google quando o usuário dá o consentimento. Os dados são coletados por app para cada app que instancia um WebView. É possível desativar essa opção recurso criando a seguinte tag no arquivo Elemento <application>:

<manifest>
    <application>
    ...
    <meta-data android:name="android.webkit.WebView.MetricsOptOut"
               android:value="true" />
    </application>
</manifest>

O upload de dados de um app só é feito com o consentimento do usuário e que o app não desative. Para mais informações sobre como desativar os dados de diagnóstico relatórios, consulte Privacidade do usuário na WebView geração de relatórios.

API Termination Handling

A API Terminal Handling lida com casos em que o processo do renderizador para um WebView desaparece, seja porque o sistema encerra o renderizador para recuperá-lo 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ça.

Se um renderizador falhar ao carregar uma página da Web específica, tentar carregar a mesma página novamente pode fazer com que um novo objeto WebView exibem 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 operar em no modo multiprocesso, você tem alguma flexibilidade na forma como o app em situações de falta de memória. É possível usar a API Renderer Importance, introduzida no Android 8.0, para definir uma política de prioridade para o renderizador atribuído a um determinado WebView. Em particular, talvez você queira que a parte principal continue a execução quando um renderizador que exibir WebView objeto foi encerrado. Você pode fazer isso, por exemplo, se esperar não mostrar o objeto WebView por muito tempo para que o sistema pode recuperar a memória que o renderizador estava usando.

O snippet de código a seguir mostra como atribuir uma prioridade ao renderizador processo 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... está vinculado: a prioridade padrão do app. O 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 o app não se importa se o sistema mantém o processo do renderizador ativo. Na verdade, esse nível de prioridade mais baixo torna provável que o processo do renderizador seja eliminado na falta de memória em diferentes situações.

Para saber mais sobre como o sistema lida com situações de pouca memória, consulte Processos e app de desenvolvimento de software.