Charger le contenu de l'application

Vous pouvez fournir à votre application du contenu Web (HTML, JavaScript et CSS, par exemple) que vous pourrez compiler de manière statique dans l'application plutôt que de le récupérer sur Internet.

Le contenu intégré à l'application ne nécessite pas d'accès à Internet et ne consomme pas de bande passante. Si le contenu est conçu spécifiquement pour WebView, c'est-à-dire qu'il dépend de la communication avec une application native, les utilisateurs ne pourront pas le charger accidentellement dans un navigateur Web.

Cependant, ce type de contenu présente quelques inconvénients. La mise à jour du contenu Web nécessite la livraison d'une nouvelle mise à jour de l'application, et il est possible que le contenu d'un site Web ne corresponde pas au contenu de l'application sur votre appareil si les utilisateurs disposent de versions obsolètes de l'application.

Composant WebViewAssetLoader

WebViewAssetLoader est un moyen flexible et performant de charger du contenu dans une application dans un objet WebView. Cette classe prend en charge les éléments suivants:

  • Chargement de contenu avec une URL HTTP(S) pour assurer la compatibilité avec la règle d'origine identique.
  • Chargement des sous-ressources telles que JavaScript, CSS, images et iFrames

Incluez WebViewAssetLoader dans le fichier d'activité principal. Voici un exemple de chargement de contenu Web simple à partir du dossier d'éléments:

Kotlin

private class LocalContentWebViewClient(private val assetLoader: WebViewAssetLoader) : WebViewClientCompat() {
    @RequiresApi(21)
    override fun shouldInterceptRequest(
        view: WebView,
        request: WebResourceRequest
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(request.url)
    }

    // To support API < 21.
    override fun shouldInterceptRequest(
        view: WebView,
        url: String
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(Uri.parse(url))
    }
}

Java

private static class LocalContentWebViewClient extends WebViewClientCompat {

    private final WebViewAssetLoader mAssetLoader;

    LocalContentWebViewClient(WebViewAssetLoader assetLoader) {
        mAssetLoader = assetLoader;
    }

    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     WebResourceRequest request) {
        return mAssetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // To support API < 21.
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     String url) {
        return mAssetLoader.shouldInterceptRequest(Uri.parse(url));
    }
}

Votre application doit configurer une instance WebViewAssetLoader en fonction de ses besoins. La section suivante contient un exemple.

Créer des composants et des ressources intégrés à l'application

WebViewAssetLoader s'appuie sur des instances PathHandler pour charger les ressources correspondant à un chemin d'accès à une ressource donné. Bien que vous puissiez implémenter cette interface pour récupérer des ressources selon les besoins de votre application, la bibliothèque Webkit regroupe AssetsPathHandler et ResourcesPathHandler pour charger les éléments et les ressources Android, respectivement.

Pour commencer, créez des composants et des ressources pour votre application. En général, les conditions suivantes s'appliquent:

  • Les fichiers texte (HTML, JavaScript et CSS, par exemple) appartiennent aux éléments.
  • Les images et les autres fichiers binaires appartiennent aux ressources.

Pour ajouter des fichiers Web texte à un projet, procédez comme suit:

  1. Dans Android Studio, effectuez un clic droit sur le dossier app > src > main, puis sélectionnez New > Directory (Nouveau > Répertoire).
    Image montrant les menus de création de répertoire d&#39;Android Studio
    Figure 1 : Créez un dossier d'éléments pour votre projet.
  2. Nommez le dossier "assets".
    Image montrant le dossier de l&#39;asset
    Figure 2. Attribuez un nom au dossier des éléments.
  3. Effectuez un clic droit sur le dossier assets, puis cliquez sur New > File (Nouveau > Fichier). Saisissez index.html, puis appuyez sur la touche Retour ou Entrée.
  4. Répétez l'étape précédente afin de créer un fichier vide pour stylesheet.css.
  5. Remplissez les fichiers vides que vous avez créés avec le contenu des deux exemples de code suivants.
```html
<!-- index.html content -->

<html>
  <head>
    <!-- Tip: Use relative URLs when referring to other in-app content to give
              your app code the flexibility to change the scheme or domain as
              necessary. -->
    <link rel="stylesheet" href="/assets/stylesheet.css">
  </head>
  <body>
    <p>This file is loaded from in-app content.</p>
    <p><img src="/res/drawable/android_robot.png" alt="Android robot" width="100"></p>
  </body>
</html>
```

```css
<!-- stylesheet.css content -->

body {
  background-color: lightblue;
}
```

Pour ajouter un fichier Web basé sur une image à votre projet, procédez comme suit:

  1. Téléchargez le fichier Android_symbol_green_RGB.png sur votre ordinateur local.

  2. Renommez le fichier android_robot.png.

  3. Déplacez manuellement le fichier dans le répertoire main/res/drawable de votre projet sur votre disque dur.

La figure 4 montre l'image que vous avez ajoutée et le texte des exemples de code précédents affiché dans une application.

Image montrant le résultat de l&#39;application
Figure 4 : Fichier HTML intégré à l'application et fichier image affichés dans une application.

Pour terminer l'application, procédez comme suit:

  1. Enregistrez les gestionnaires et configurez le AssetLoader en ajoutant le code suivant à la méthode onCreate():

    Kotlin

    val assetLoader = WebViewAssetLoader.Builder()
                           .addPathHandler("/assets/", AssetsPathHandler(this))
                           .addPathHandler("/res/", ResourcesPathHandler(this))
                           .build()
    webView.webViewClient = LocalContentWebViewClient(assetLoader)
    

    Java

    final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
             .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
             .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this))
             .build();
    mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
    
  2. Chargez le contenu en ajoutant le code suivant à la méthode onCreate():

    Kotlin

    webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
    

    Java

    mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
    

Combinez le contenu de l'application avec des ressources de votre site Web

Votre application peut avoir besoin de charger un mélange de contenu intégré et de contenu provenant d'Internet, comme une page HTML intégrée au style CSS de votre site Web. WebViewAssetLoader prend en charge ce cas d'utilisation. Si aucune des instances PathHandler enregistrées ne parvient à trouver une ressource pour le chemin d'accès donné, WebView se rabat sur le chargement du contenu depuis Internet. Si vous combinez du contenu intégré à l'application avec des ressources de votre site Web, réservez les chemins d'accès au répertoire, tels que /assets/ ou /resources/, pour les ressources intégrées à l'application. Évitez de stocker les ressources de votre site Web à ces emplacements.

Kotlin

val assetLoader = WebViewAssetLoader.Builder()
                        .setDomain("example.com") // Replace this with your website's domain.
                        .addPathHandler("/assets/", AssetsPathHandler(this))
                        .build()

webView.webViewClient = LocalContentWebViewClient(assetLoader)
val inAppHtmlUrl = "https://example.com/assets/index.html"
webView.loadUrl(inAppHtmlUrl)
val websiteUrl = "https://example.com/website/data.json"

// JavaScript code to fetch() content from the same origin.
val jsCode = "fetch('$websiteUrl')" +
        ".then(resp => resp.json())" +
        ".then(data => console.log(data));"

webView.evaluateJavascript(jsCode, null)

Java

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
           .setDomain("example.com") // Replace this with your website's domain.
           .addPathHandler("/assets/", new AssetsPathHandler(this))
           .build();

mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
String inAppHtmlUrl = "https://example.com/assets/index.html";
mWebView.loadUrl(inAppHtmlUrl);
String websiteUrl = "https://example.com/website/data.json";

// JavaScript code to fetch() content from the same origin.
String jsCode = "fetch('" + websiteUrl + "')" +
      ".then(resp => resp.json())" +
      ".then(data => console.log(data));";

mWebView.evaluateJavascript(jsCode, null);

Consultez la démonstration de WebView sur GitHub pour voir un exemple de page HTML intégrée à l'application récupérant des données JSON hébergées sur le Web.

loadDataWithBaseURL

Lorsque votre application a uniquement besoin de charger une page HTML et n'a pas besoin d'intercepter des sous-ressources, envisagez d'utiliser loadDataWithBaseURL(), qui ne nécessite pas de composants d'application. Vous pouvez l'utiliser comme indiqué dans l'exemple de code suivant:

Kotlin

val html = "<html><body><p>Hello world</p></body></html>"
val baseUrl = "https://example.com/"

webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)

Java

String html = "<html><body><p>Hello world</p></body></html>";
String baseUrl = "https://example.com/";

mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);

Choisissez les valeurs d'argument avec précaution. Réfléchissez aux points suivants :

  • baseUrl: URL sous laquelle votre contenu HTML est chargé. Il doit s'agir d'une URL HTTP(S).
  • data: contenu HTML que vous souhaitez afficher, sous forme de chaîne.
  • mimeType: il doit généralement être défini sur text/html.
  • encoding: cet élément n'est pas utilisé lorsque baseUrl est une URL HTTP(S). Il peut donc être défini sur null.
  • historyUrl: défini sur la même valeur que baseUrl.

Nous vous recommandons vivement d'utiliser une URL HTTP(S) comme baseUrl, car cela permet de garantir que votre application respecte les règles concernant les mêmes origines.

Si vous ne trouvez pas de baseUrl adapté à votre contenu et que vous préférez utiliser loadData(), vous devez encoder le contenu à l'aide d'un encodage-pourcent ou d'encodage en base64. Nous vous recommandons vivement de choisir l'encodage Base64 et d'utiliser les API Android pour l'encoder par programmation, comme illustré dans l'exemple de code suivant:

Kotlin

val encodedHtml: String = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING)

webView.loadData(encodedHtml, mimeType, "base64")

Java

String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);

mWebView.loadData(encodedHtml, mimeType, "base64");

Ce qu'il faut éviter

Il existe plusieurs autres façons de charger du contenu intégré à l'application, mais nous vous recommandons vivement de les utiliser:

  • Les URL file:// et data: sont considérées comme des origines opaques, ce qui signifie qu'elles ne peuvent pas bénéficier d'API Web puissantes telles que fetch() ou XMLHttpRequest. loadData() utilise des URL data: en interne. Nous vous recommandons donc d'utiliser WebViewAssetLoader ou loadDataWithBaseURL() à la place.
  • Bien que WebSettings.setAllowFileAccessFromFileURLs() et WebSettings.setAllowUniversalAccessFromFileURLs() puissent contourner les problèmes liés aux URL file://, nous vous recommandons de ne pas les définir sur true, car cela rend votre application vulnérable aux failles basées sur les fichiers. Pour plus de sécurité, nous vous recommandons de les définir explicitement sur false pour tous les niveaux d'API.
  • Pour les mêmes raisons, nous vous déconseillons d'utiliser les URL file://android_assets/ et file://android_res/. Les classes AssetsHandler et ResourcesHandler sont destinées à être remplacées.
  • Évitez d'utiliser MIXED_CONTENT_ALWAYS_ALLOW. De manière générale, ce paramètre affaiblit la sécurité de votre application. Nous vous recommandons de charger le contenu de votre application sur le même schéma (HTTP ou HTTPS) que les ressources de votre site Web, et d'utiliser MIXED_CONTENT_COMPATIBILITY_MODE ou MIXED_CONTENT_NEVER_ALLOW, selon le cas.