WebView-Objekte verwalten

Android bietet verschiedene APIs, mit denen du die WebView-Objekte verwalten kannst, die Webinhalte in deiner App darstellen.

Auf dieser Seite wird beschrieben, wie du diese APIs verwenden kannst, um effektiver mit WebView-Objekten zu arbeiten und so die Stabilität und Sicherheit deiner App zu verbessern.

Versions-API

Ab Android 7.0 (API-Level 24) können Nutzer aus verschiedenen Paketen für die Anzeige von Webinhalten in einem WebView-Objekt auswählen. Die Bibliothek AndroidX.webkit enthält die Methode getCurrentWebViewPackage() zum Abrufen von Informationen zu dem Paket, das Webinhalte in Ihrer App anzeigt. Diese Methode ist nützlich, um Fehler zu analysieren, die nur auftreten, wenn Ihre App versucht, Webinhalte mithilfe der Implementierung von WebView eines bestimmten Pakets anzuzeigen.

Um diese Methode zu verwenden, fügen Sie die im folgenden Code-Snippet gezeigte Logik hinzu:

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

Safe Browsing-Dienst von Google

Um das Surfen für Ihre Nutzer sicherer zu machen, verifizieren WebView-Objekte URLs mithilfe von Google Safe Browsing. Ihre App zeigt dann Nutzern eine Warnung an, wenn sie versuchen, eine potenziell unsichere Website aufzurufen.

Auch wenn der Standardwert von EnableSafeBrowsing „true“ ist, kann es Fälle geben, in denen Sie Safe Browsing nur bedingt aktivieren oder deaktivieren möchten. Android 8.0 (API-Level 26) und höher unterstützt die Verwendung von setSafeBrowsingEnabled() zum Umschalten von Safe Browsing für ein einzelnes WebView-Objekt.

Wenn Sie möchten, dass für alle WebView-Objekte Safe Browsing-Prüfungen deaktiviert werden, fügen Sie der Manifestdatei Ihrer App das folgende <meta-data>-Element hinzu:

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

Programmatische Aktionen definieren

Wenn eine Instanz von WebView versucht, eine Seite zu laden, die von Google als bekannte Bedrohung eingestuft wurde, zeigt WebView standardmäßig ein Interstitial an, das Nutzer vor der bekannten Bedrohung warnt. Auf diesem Bildschirm haben Nutzer die Möglichkeit, die URL trotzdem zu laden oder zu einer vorherigen, sicheren Seite zurückzukehren.

Wenn Sie Ihre App auf Android 8.1 (API-Level 27) oder höher ausrichten, können Sie folgendermaßen programmatisch definieren, wie Ihre App auf eine bekannte Bedrohung reagiert:

  • Sie können festlegen, ob Ihre App bekannte Bedrohungen an Safe Browsing meldet.
  • Sie können festlegen, dass Ihre App jedes Mal automatisch eine bestimmte Aktion ausführt – z. B. das Zurückkehren in die Sicherheit –, wenn sie auf eine URL stößt, die als bekannte Bedrohung eingestuft ist.

Die folgenden Code-Snippets zeigen, wie Sie die Instanzen von WebView in Ihrer App anweisen, nach dem Auftreten einer bekannten Bedrohung immer wieder in Sicherheit zu kommen:

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

HTML5 Geolocation API

Bei Apps, die auf Android 6.0 (API-Level 23) und höher ausgerichtet sind, wird die Geolocation API nur für sichere Ursprünge wie HTTPS unterstützt. Alle Anfragen an die Geolocation API von nicht sicheren Ursprüngen werden automatisch abgelehnt, ohne die entsprechende onGeolocationPermissionsShowPrompt()-Methode aufzurufen.

Messwerterfassung deaktivieren

WebView hat die Möglichkeit, anonyme Diagnosedaten in Google hochzuladen, wenn der Nutzer seine Einwilligung erteilt. Die Daten werden pro App für jede App erhoben, die ein WebView instanziiert. Du kannst diese Funktion deaktivieren, indem du das folgende Tag im <application>-Element des Manifests erstellst:

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

Daten werden nur von einer App hochgeladen, wenn der Nutzer einwilligt und die App dies nicht deaktiviert. Weitere Informationen zum Deaktivieren der Berichterstellung zu Diagnosedaten finden Sie unter Datenschutz für Nutzer in WebView-Berichten.

Beendigungsbehandlungs-API

Die Termination Handling API ist für Fälle vorgesehen, in denen der Renderer-Prozess für ein WebView-Objekt nicht mehr ausgeführt wird. Dies kann der Fall sein, weil das System den Renderer beendet, um den erforderlichen Arbeitsspeicher freizugeben, oder der Renderer-Prozess abstürzt. Mit dieser API wird die Ausführung Ihrer App fortgesetzt, auch wenn der Rendererprozess eingestellt wird.

Wenn ein Renderer beim Laden einer bestimmten Webseite abstürzt, kann der Versuch, dieselbe Seite noch einmal zu laden, dazu führen, dass ein neues WebView-Objekt dasselbe Rendering-Absturzverhalten aufweist.

Das folgende Code-Snippet zeigt, wie diese API in einem Activity verwendet wird:

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

Renderer Importance API

Wenn WebView-Objekte im Multiprozessmodus ausgeführt werden, können Sie flexibel entscheiden, wie Ihre Anwendung mit unzureichendem Arbeitsspeicher umgeht. Mit der in Android 8.0 eingeführten Renderer Importance API kannst du eine Prioritätsrichtlinie für den Renderer festlegen, der einem bestimmten WebView-Objekt zugewiesen ist. Insbesondere soll die Ausführung des Hauptteils Ihrer Anwendung fortgesetzt werden, wenn ein Renderer, der die WebView-Objekte Ihrer App anzeigt, beendet wird. Das ist beispielsweise sinnvoll, wenn das Objekt WebView über einen längeren Zeitraum nicht angezeigt werden soll, damit das System Arbeitsspeicher zurückfordern kann, den der Renderer verwendet hat.

Das folgende Code-Snippet zeigt, wie Sie dem Renderer-Prozess, der den WebView-Objekten Ihrer App zugeordnet ist, eine Priorität zuweisen:

Kotlin

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

Java

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

In diesem Snippet ist die Priorität des Renderers mit der Standardpriorität für die App identisch oder an diese gebunden. Durch das Argument true wird die Priorität des Renderers auf RENDERER_PRIORITY_WAIVED gesenkt, wenn das verknüpfte WebView-Objekt nicht mehr sichtbar ist. Mit anderen Worten: Ein true-Argument gibt an, dass es für Ihre App keine Rolle spielt, ob das System den Rendererprozess aktiv hält. Diese niedrigere Prioritätsstufe führt sogar dazu, dass der Renderer-Prozess bei Situationen mit unzureichendem Arbeitsspeicher abgebrochen wird.

Weitere Informationen dazu, wie das System mit Situationen mit wenig Arbeitsspeicher umgeht, finden Sie unter Prozesse und Anwendungslebenszyklus.