Gérer les objets WebView

Android fournit plusieurs API pour vous aider à gérer les objets WebView qui affichent du contenu Web dans votre application.

Cette page explique comment utiliser ces API pour travailler plus efficacement avec les objets WebView, et ainsi améliorer la stabilité et la sécurité de votre application.

Version de l'API

À partir d'Android 7.0 (niveau d'API 24), les utilisateurs peuvent choisir parmi plusieurs packages pour afficher du contenu Web dans un objet WebView. La bibliothèque AndroidX.webkit inclut la méthode getCurrentWebViewPackage() pour récupérer les informations liées au package qui affiche le contenu Web dans votre application. Cette méthode est utile pour analyser les erreurs qui ne se produisent que lorsque votre application tente d'afficher du contenu Web à l'aide de l'implémentation de WebView d'un package particulier.

Pour utiliser cette méthode, ajoutez la logique illustrée dans l'extrait de code suivant:

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

Service de navigation sécurisée Google

Pour offrir à vos utilisateurs une expérience de navigation plus sûre, les objets WebView valident les URL à l'aide de la navigation sécurisée Google, qui permet à votre application d'afficher un avertissement aux utilisateurs lorsqu'ils tentent d'accéder à un site Web potentiellement dangereux.

Bien que la valeur par défaut de EnableSafeBrowsing soit "true", il peut arriver que vous souhaitiez n'activer la navigation sécurisée que de manière conditionnelle ou la désactiver. Android 8.0 (niveau d'API 26) ou version ultérieure est compatible avec l'utilisation de setSafeBrowsingEnabled() afin d'activer ou de désactiver la navigation sécurisée pour un objet WebView individuel.

Si vous souhaitez que tous les objets WebView désactivent les vérifications de la navigation sécurisée, ajoutez l'élément <meta-data> suivant au fichier manifeste de votre application:

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

Définir des actions programmatiques

Lorsqu'une instance de WebView tente de charger une page classée par Google comme menace connue, WebView affiche par défaut un interstitiel avertissant les utilisateurs de la menace connue. Cet écran permet aux utilisateurs de charger l'URL quand même ou de revenir à une page précédente sûre.

Si vous ciblez Android 8.1 (niveau d'API 27) ou une version ultérieure, vous pouvez définir de manière programmatique la manière dont votre application réagit à une menace connue comme suit:

  • Vous pouvez contrôler si votre application signale les menaces connues à la navigation sécurisée.
  • Vous pouvez demander à votre application d'effectuer automatiquement une action particulière (comme revenir en lieu sûr) chaque fois qu'elle rencontre une URL classée comme menace connue.

Les extraits de code suivants montrent comment indiquer aux instances de WebView de votre application de toujours revenir en lieu sûr après avoir rencontré une menace connue:

MonActivitéWebWeb.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

Pour les applications ciblant Android 6.0 (niveau d'API 23) ou version ultérieure, l'API Geolocation n'est compatible qu'avec les origines sécurisées, telles que HTTPS. Toute requête envoyée à l'API Geolocation sur des origines non sécurisées est automatiquement refusée sans appeler la méthode onGeolocationPermissionsShowPrompt() correspondante.

Désactiver la collecte de métriques

WebView peut importer des données de diagnostic anonymes sur Google lorsque l'utilisateur donne son consentement. Les données sont collectées par application pour chaque application qui instancie un WebView. Vous pouvez désactiver cette fonctionnalité en créant la balise suivante dans l'élément <application> du fichier manifeste:

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

Les données ne sont importées à partir d'une application que si l'utilisateur donne son consentement et si l'application ne les désactive pas. Pour savoir comment désactiver la création de rapports sur les données de diagnostic, consultez Confidentialité des utilisateurs dans les rapports WebView.

API de gestion des terminaisons

Elle gère les cas où le processus de moteur de rendu d'un objet WebView disparaît, soit parce que le système l'arrête pour récupérer la mémoire nécessaire, soit parce qu'il plante. En utilisant cette API, vous permettez à votre application de continuer à s'exécuter même si le processus du moteur de rendu disparaît.

Si un moteur de rendu plante lors du chargement d'une page Web spécifique, le fait d'essayer de charger à nouveau cette même page peut entraîner le même comportement de plantage de l'affichage qu'un nouvel objet WebView.

L'extrait de code suivant montre comment utiliser cette API dans 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

Lorsque les objets WebView fonctionnent en mode multiprocessus, vous pouvez gérer les cas de mémoire insuffisante par votre application. Vous pouvez utiliser l'API Renderer Importance, introduite dans Android 8.0, pour définir une règle de priorité pour le moteur de rendu attribué à un objet WebView particulier. Vous pouvez en particulier souhaiter que la partie principale de votre application continue de s'exécuter lorsqu'un moteur de rendu qui affiche les objets WebView de votre application est arrêté. Cela peut se produire, par exemple, si vous prévoyez de ne pas afficher l'objet WebView pendant une longue période afin que le système puisse récupérer la mémoire utilisée par le moteur de rendu.

L'extrait de code suivant montre comment attribuer une priorité au processus du moteur de rendu associé aux objets WebView de votre application:

Kotlin

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

Java

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

Dans cet extrait de code, la priorité du moteur de rendu est identique ou liée à la priorité par défaut de l'application. L'argument true réduit la priorité du moteur de rendu à RENDERER_PRIORITY_WAIVED lorsque l'objet WebView associé n'est plus visible. En d'autres termes, un argument true indique que votre application ne se soucie pas du fait que le système maintient actif le processus de moteur de rendu. En fait, avec ce niveau de priorité inférieur, il est probable que le processus du moteur de rendu soit arrêté en cas de mémoire insuffisante.

Pour en savoir plus sur la manière dont le système gère les situations de mémoire insuffisante, consultez la section Processus et cycle de vie d'une application.