Gestisci oggetti WebView

Android fornisce diverse API per aiutarti a gestire gli oggetti WebView che mostrano i contenuti web nella tua app.

In questa pagina viene descritto come utilizzare queste API per lavorare con gli oggetti WebView in modo più efficace, migliorando la stabilità e la sicurezza della tua app.

API Version

A partire da Android 7.0 (livello API 24), gli utenti possono scegliere tra diversi pacchetti per la visualizzazione di contenuti web in un oggetto WebView. La libreria AndroidX.webkit include il metodo getCurrentWebViewPackage() per recuperare le informazioni relative al pacchetto che mostra contenuti web nella tua app. Questo metodo è utile per analizzare gli errori che si verificano solo quando l'app tenta di visualizzare contenuti web usando l'implementazione di WebView di un determinato pacchetto.

Per utilizzare questo metodo, aggiungi la logica mostrata nel seguente snippet di codice:

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);

Servizio Google Navigazione sicura

Per offrire agli utenti un'esperienza di navigazione più sicura, gli oggetti WebView verificano gli URL utilizzando Google Navigazione sicura, che consente alla tua app di mostrare agli utenti un avviso quando tentano di visitare un sito web potenzialmente non sicuro.

Anche se il valore predefinito di EnableSafeBrowsing è true, in alcuni casi potrebbe essere opportuno attivare Navigazione sicura solo in modo condizionale o disabilitarla. Android 8.0 (livello API 26) e versioni successive supporta l'utilizzo di setSafeBrowsingEnabled() per attivare/disattivare Navigazione sicura per un singolo oggetto WebView.

Se vuoi che tutti gli oggetti WebView disattivino i controlli di Navigazione sicura, aggiungi il seguente elemento <meta-data> al file manifest della tua app:

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

Definisci azioni programmatiche

Quando un'istanza di WebView tenta di caricare una pagina che è classificata da Google come minaccia nota, per impostazione predefinita WebView mostra un interstitial che avvisa gli utenti della minaccia nota. Questa schermata offre agli utenti la possibilità di caricare comunque l'URL o di tornare a una pagina precedente sicura.

Se scegli come target Android 8.1 (livello API 27) o versioni successive, puoi definire in modo programmatico in che modo la tua app risponde a una minaccia nota nei seguenti modi:

  • Puoi controllare se la tua app segnala minacce note a Navigazione sicura.
  • Puoi fare in modo che la tua app esegua automaticamente una determinata azione, ad esempio tornare nell'area protetta, ogni volta che rileva un URL classificato come minaccia nota.

I seguenti snippet di codice mostrano come indicare alle istanze della tua app di WebView di tornare sempre in sicurezza dopo che si sono verificate una minaccia nota:

AttivitàWeb.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

Per le app che hanno come target Android 6.0 (livello API 23) e versioni successive, l'API Geolocation è supportata solo su origini sicure, come HTTPS. Qualsiasi richiesta all'API Geolocation su origini non sicure viene automaticamente rifiutata senza richiamare il metodo onGeolocationPermissionsShowPrompt() corrispondente.

Disattiva la raccolta di metriche

WebView può caricare dati diagnostici anonimi su Google quando l'utente dà il consenso. I dati vengono raccolti per singola app per ogni app che crea un'istanza di WebView. Per disattivare questa funzionalità, crea il seguente tag nell'elemento <application> del file manifest:

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

I dati vengono caricati da un'app solo se l'utente acconsente e l'app non disattiva la disattivazione. Per ulteriori informazioni sulla disattivazione della segnalazione dei dati diagnostici, consulta Privacy utente nei report di WebView.

API Terminazione Gestione

L'API Terminare handling gestisce i casi in cui il processo di rendering di un oggetto WebView scompare perché il sistema termina il renderer per recuperare la memoria necessaria o perché il processo del renderer si arresta in modo anomalo. Questa API consente all'app di continuare a essere eseguita, anche se il processo di rendering scompare.

Se un renderer si arresta in modo anomalo durante il caricamento di una pagina web specifica, il tentativo di caricare di nuovo la stessa pagina potrebbe causare lo stesso comportamento di arresto anomalo di un nuovo oggetto WebView.

Il seguente snippet di codice illustra come utilizzare questa API in un 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 gli oggetti WebView operano in modalità multiprocesso, hai una certa flessibilità nel modo in cui l'app gestisce le situazioni di esaurimento della memoria. Puoi utilizzare l'API Renderer Importance, introdotta in Android 8.0, per impostare un criterio di priorità per il renderer assegnato a un particolare oggetto WebView. In particolare, potresti voler fare in modo che la parte principale dell'app continui a essere eseguita quando viene terminato un renderer che mostra gli oggetti WebView dell'app. Puoi farlo, ad esempio, se ti aspetti di non mostrare l'oggetto WebView per molto tempo, in modo che il sistema possa recuperare la memoria utilizzata dal renderer.

Il seguente snippet di codice mostra come assegnare una priorità al processo di rendering associato agli oggetti WebView dell'app:

Kotlin

val myWebView: WebView = ...
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)

Java

WebView myWebView;
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);

In questo particolare snippet, la priorità del renderer è uguale, o è vincolata, alla priorità predefinita per l'app. L'argomento true diminuisce la priorità del renderer a RENDERER_PRIORITY_WAIVED quando l'oggetto WebView associato non è più visibile. In altre parole, un argomento true indica che all'app non importa se il sistema mantiene attivo il processo di rendering. In effetti, questo livello di priorità più basso rende probabile che il processo del renderer venga interrotto in situazioni di esaurimento della memoria.

Per scoprire di più su come il sistema gestisce le situazioni con memoria ridotta, consulta Processi e ciclo di vita delle app.