Créer des applications Web dans WebView

Utilisez WebView pour diffuser une application Web ou une page Web dans le cadre d'une application cliente. La classe WebView est une extension de la classe View d'Android qui vous permet d'afficher des pages Web dans la mise en page de votre activité. Elle n'inclut pas les fonctionnalités d'un navigateur Web entièrement développé, telles que les commandes de navigation ou une barre d'adresse. Par défaut, WebView affiche une page Web uniquement.

WebView peut vous aider à fournir dans votre application des informations que vous devrez peut-être mettre à jour, comme un contrat utilisateur final ou un guide de l'utilisateur. Dans votre application Android, vous pouvez créer un Activity contenant un élément WebView, puis l'utiliser pour afficher votre document hébergé en ligne.

WebView peut également être utile lorsque votre application fournit des données à l'utilisateur qui a besoin d'une connexion Internet pour récupérer des données, telles que des e-mails. Dans ce cas, vous constaterez peut-être qu'il est plus facile de créer un WebView dans votre application Android qui affiche une page Web avec toutes les données utilisateur, plutôt que d'exécuter une requête réseau, puis d'analyser les données et de les afficher dans une mise en page Android. À la place, vous pouvez concevoir une page Web adaptée aux appareils Android, puis implémenter dans votre application Android un WebView qui charge la page Web.

Ce document explique comment démarrer avec WebView, lier du code JavaScript à partir de votre page Web au code côté client dans votre application Android, gérer la navigation sur les pages et les fenêtres lorsque vous utilisez WebView.

Utiliser WebView sur des versions antérieures d'Android

Pour utiliser les fonctionnalités WebView plus récentes de manière sécurisée sur l'appareil sur lequel votre application s'exécute, ajoutez la bibliothèque AndroidX Webkit. Il s'agit d'une bibliothèque statique que vous pouvez ajouter à votre application pour utiliser les API android.webkit qui ne sont pas disponibles pour les versions antérieures de la plate-forme.

Ajoutez-le à votre fichier build.gradle comme suit:

Kotlin

dependencies {
    implementation("androidx.webkit:webkit:1.8.0")
}

Groovy

dependencies {
    implementation ("androidx.webkit:webkit:1.8.0")
}

Explorez l'exemple WebView sur GitHub pour en savoir plus.

Ajouter une WebView à votre application

Pour ajouter un WebView à votre application, vous pouvez inclure l'élément <WebView> dans la mise en page de votre activité ou définir l'intégralité de la fenêtre Activity en tant que WebView dans onCreate().

Ajouter une WebView dans la mise en page de l'activité

Pour ajouter un WebView à votre application dans la mise en page, ajoutez le code suivant au fichier XML de mise en page de votre activité:

<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>

Pour charger une page Web dans WebView, utilisez loadUrl(), comme illustré dans l'exemple suivant:

Kotlin

val myWebView: WebView = findViewById(R.id.webview)
myWebView.loadUrl("http://www.example.com")

Java

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");

Ajouter une WebView dans onCreate()

Pour ajouter un WebView à votre application dans la méthode onCreate() d'une activité, utilisez plutôt une logique semblable à la suivante:

Kotlin

val myWebView = WebView(activityContext)
setContentView(myWebView)

Java

WebView myWebView = new WebView(activityContext);
setContentView(myWebView);

Chargez ensuite la page:

Kotlin

myWebView.loadUrl("http://www.example.com")

Java

myWebView.loadUrl("https://www.example.com");

Ou chargez l'URL à partir d'une chaîne HTML:

Kotlin

// Create an unencoded HTML string, then convert the unencoded HTML string into
// bytes. Encode it with base64 and load the data.
val unencodedHtml =
     "<html><body>'%23' is the percent code for ‘#‘ </body></html>";
val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING)
myWebView.loadData(encodedHtml, "text/html", "base64")

Java

// Create an unencoded HTML string, then convert the unencoded HTML string into
// bytes. Encode it with base64 and load the data.
String unencodedHtml =
     "<html><body>'%23' is the percent code for ‘#‘ </body></html>";
String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(),
        Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");

Votre application doit avoir accès à Internet. Pour obtenir un accès à Internet, demandez l'autorisation INTERNET dans le fichier manifeste, comme indiqué dans l'exemple suivant:

<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

Vous pouvez personnaliser votre WebView en effectuant l'une des opérations suivantes:

  • Activation du mode plein écran à l'aide de WebChromeClient Cette classe est également appelée lorsqu'un WebView a besoin d'une autorisation pour modifier l'interface utilisateur de l'application hôte, par exemple pour créer ou fermer des fenêtres, ou pour envoyer des boîtes de dialogue JavaScript à l'utilisateur. Pour en savoir plus sur le débogage dans ce contexte, consultez Déboguer des applications Web.
  • Gestion des événements qui ont une incidence sur l'affichage du contenu, tels que les erreurs lors de l'envoi de formulaires ou de la navigation à l'aide de WebViewClient Vous pouvez également utiliser cette sous-classe pour intercepter le chargement des URL.
  • Activer JavaScript en modifiant WebSettings
  • Utiliser JavaScript pour accéder aux objets du framework Android que vous avez injectés dans un WebView.

Utiliser JavaScript dans WebView

Si la page Web que vous souhaitez charger dans votre WebView utilise JavaScript, vous devez l'activer pour votre WebView. Après avoir activé JavaScript, vous pouvez créer des interfaces entre le code de votre application et votre code JavaScript.

Activer JavaScript

JavaScript est désactivé par défaut dans les WebView. Vous pouvez l'activer via le WebSettings associé à votre WebView. Récupérez WebSettings avec getSettings(), puis activez JavaScript avec setJavaScriptEnabled().

Consultez l'exemple suivant :

Kotlin

val myWebView: WebView = findViewById(R.id.webview)
myWebView.settings.javaScriptEnabled = true

Java

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

WebSettings permet d'accéder à un certain nombre d'autres paramètres qui pourraient vous être utiles. Par exemple, si vous développez une application Web spécialement conçue pour WebView dans votre application Android, vous pouvez définir une chaîne user-agent personnalisée avec setUserAgentString(), puis interroger le user-agent personnalisé sur votre page Web pour vérifier que le client qui demande votre page Web est votre application Android.

Lier du code JavaScript au code Android

Lorsque vous développez une application Web spécialement conçue pour WebView dans votre application Android, vous pouvez créer des interfaces entre votre code JavaScript et le code Android côté client. Par exemple, votre code JavaScript peut appeler une méthode dans votre code Android pour afficher un élément Dialog, au lieu d'utiliser la fonction alert() de JavaScript.

Pour lier une nouvelle interface entre votre code JavaScript et Android, appelez addJavascriptInterface(), en lui transmettant une instance de classe à lier à votre code JavaScript et un nom d'interface que votre code JavaScript peut appeler pour accéder à la classe.

Par exemple, vous pouvez inclure la classe suivante dans votre application Android:

Kotlin

/** Instantiate the interface and set the context.  */
class WebAppInterface(private val mContext: Context) {

    /** Show a toast from the web page.  */
    @JavascriptInterface
    fun showToast(toast: String) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()
    }
}

Java

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context. */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page. */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

Dans cet exemple, la classe WebAppInterface permet à la page Web de créer un message Toast à l'aide de la méthode showToast().

Vous pouvez lier cette classe au JavaScript qui s'exécute dans votre WebView avec addJavascriptInterface(), comme illustré dans l'exemple suivant:

Kotlin

val webView: WebView = findViewById(R.id.webview)
webView.addJavascriptInterface(WebAppInterface(this), "Android")

Java

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

Cela crée une interface appelée Android pour JavaScript s'exécutant dans WebView. À ce stade, l'application Web a accès à la classe WebAppInterface. Par exemple, les codes HTML et JavaScript ci-dessous permettent de générer un toast à l'aide de la nouvelle interface lorsque l'utilisateur appuie sur un bouton:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

Il n'est pas nécessaire d'initialiser l'interface Android à partir de JavaScript. WebView le met automatiquement à disposition sur votre page Web. Ainsi, lorsqu'un utilisateur appuie sur le bouton, la fonction showAndroidToast() utilise l'interface Android pour appeler la méthode WebAppInterface.showToast().

Gérer la navigation sur les pages

Lorsque l'utilisateur appuie sur un lien à partir d'une page Web dans votre WebView, Android lance par défaut une application qui gère les URL. En général, le navigateur Web par défaut ouvre et charge l'URL de destination. Toutefois, vous pouvez ignorer ce comportement pour votre WebView afin que les liens s'ouvrent dans votre WebView. Vous pouvez ensuite laisser l'utilisateur passer d'un historique de page Web à un autre, géré par votre WebView.

Pour ouvrir les liens sur lesquels l'utilisateur s'appuie, fournissez un WebViewClient pour votre WebView à l'aide de setWebViewClient(). Tous les liens sur lesquels l'utilisateur appuie se chargent dans votre WebView. Si vous souhaitez mieux contrôler l'emplacement de chargement d'un lien sur lequel l'utilisateur a cliqué, créez votre propre WebViewClient qui remplace la méthode shouldOverrideUrlLoading(). L'exemple suivant suppose que MyWebViewClient est une classe interne de Activity.

Kotlin

private class MyWebViewClient : WebViewClient() {

    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        if (Uri.parse(url).host == "www.example.com") {
            // This is your website, so don't override. Let your WebView load
            // the page.
            return false
        }
        // Otherwise, the link isn't for a page on your site, so launch another
        // Activity that handles URLs.
        Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
            startActivity(this)
        }
        return true
    }
}

Java

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        if ("www.example.com".equals(request.getUrl().getHost())) {
      // This is your website, so don't override. Let your WebView load the
      // page.
      return false;
    }
    // Otherwise, the link isn't for a page on your site, so launch another
    // Activity that handles URLs.
    Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
    startActivity(intent);
    return true;
  }
}

Créez ensuite une instance de ce nouveau WebViewClient pour WebView:

Kotlin

val myWebView: WebView = findViewById(R.id.webview)
myWebView.webViewClient = MyWebViewClient()

Java

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());

Désormais, lorsque l'utilisateur appuie sur un lien, le système appelle la méthode shouldOverrideUrlLoading(), qui vérifie si l'hôte de l'URL correspond à un domaine spécifique, comme défini dans l'exemple précédent. Si tel est le cas, la méthode renvoie la valeur "false" et ne remplace pas le chargement de l'URL. Elle permet à WebView de charger l'URL comme d'habitude. Si l'hôte de l'URL ne correspond pas, une Intent est créée pour lancer l'Activity par défaut pour la gestion des URL, qui renvoie au navigateur Web par défaut de l'utilisateur.

Gérer les URL personnalisées

WebView applique des restrictions lors des demandes de ressources et de la résolution des liens qui utilisent un schéma d'URL personnalisé. Par exemple, si vous implémentez des rappels tels que shouldOverrideUrlLoading() ou shouldInterceptRequest(), WebView ne les appelle que pour des URL valides.

Par exemple, WebView peut ne pas appeler votre méthode shouldOverrideUrlLoading() pour les liens de ce type:

<a href="showProfile">Show Profile</a>

Les URL non valides, comme celle illustrée dans l'exemple précédent, sont traitées de manière incohérente dans WebView. Nous vous recommandons donc d'utiliser plutôt une URL au bon format. Vous pouvez utiliser un schéma personnalisé ou une URL HTTPS pour un domaine contrôlé par votre organisation.

Au lieu d'utiliser une simple chaîne dans un lien, comme dans l'exemple précédent, vous pouvez utiliser un schéma personnalisé comme celui-ci:

<a href="example-app:showProfile">Show Profile</a>

Vous pouvez ensuite gérer cette URL dans la méthode shouldOverrideUrlLoading() comme suit:

Kotlin

// The URL scheme must be non-hierarchical, meaning no trailing slashes.
const val APP_SCHEME = "example-app:"

override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
    return if (url?.startsWith(APP_SCHEME) == true) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8")
        respondToData(urlData)
        true
    } else {
        false
    }
}

Java

// The URL scheme must be non-hierarchical, meaning no trailing slashes.
private static final String APP_SCHEME = "example-app:";

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith(APP_SCHEME)) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
        respondToData(urlData);
        return true;
    }
    return false;
}

L'API shouldOverrideUrlLoading() est principalement destinée à lancer des intents pour des URL spécifiques. Lorsque vous l'implémentez, veillez à renvoyer false pour les URL que WebView gère. Vous n'êtes toutefois pas limité au lancement des intents. Vous pouvez remplacer le lancement des intents par l'un des comportements personnalisés indiqués dans les exemples de code précédents.

Lorsque votre WebView remplace le chargement de l'URL, il accumule automatiquement un historique des pages Web consultées. Vous pouvez passer à l'étape précédente ou suivante dans l'historique avec goBack() et goForward().

Par exemple, voici comment votre Activity peut utiliser le bouton "Retour" de l'appareil pour revenir en arrière:

Kotlin

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    // Check whether the key event is the Back button and if there's history.
    if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
        myWebView.goBack()
        return true
    }
    // If it isn't the Back button or there isn't web page history, bubble up to
    // the default system behavior. Probably exit the activity.
    return super.onKeyDown(keyCode, event)
}

Java

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check whether the key event is the Back button and if there's history.
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    // If it isn't the Back button or there's no web page history, bubble up to
    // the default system behavior. Probably exit the activity.
    return super.onKeyDown(keyCode, event);
}

Si votre application utilise AndroidX AppCompat 1.6.0 ou une version ultérieure, vous pouvez encore simplifier davantage l'extrait précédent:

Kotlin

onBackPressedDispatcher.addCallback {
    // Check whether there's history.
    if (myWebView.canGoBack()) {
        myWebView.goBack()
    }
}

Java

onBackPressedDispatcher.addCallback {
    // Check whether there's history.
    if (myWebView.canGoBack()) {
        myWebView.goBack();
    }
}

La méthode canGoBack() renvoie la valeur "true" si l'utilisateur dispose d'un historique des pages Web à consulter. De même, vous pouvez vérifier s'il existe un historique de transfert à l'aide de canGoForward(). Si vous n'effectuez pas cette vérification, goBack() et goForward() n'ont aucune incidence une fois que l'utilisateur a atteint la fin de l'historique.

Gérer les modifications de configuration des appareils

Pendant l'exécution, l'état d'une activité change lorsque la configuration d'un appareil change, par exemple lorsque les utilisateurs font pivoter l'appareil ou ignorent un éditeur de mode de saisie (IME). Ces modifications entraînent la destruction de l'activité d'un objet WebView et la création d'une activité, ce qui crée également un objet WebView qui charge l'URL de l'objet détruit. Pour modifier le comportement par défaut de votre activité, vous pouvez modifier la façon dont elle gère les modifications de orientation dans votre fichier manifeste. Pour en savoir plus sur la gestion des modifications de configuration pendant l'exécution, consultez Gérer les modifications de configuration.

Gérer les fenêtres

Par défaut, les demandes d'ouverture de nouvelles fenêtres sont ignorées. Cela est vrai qu'elles soient ouvertes par JavaScript ou par l'attribut cible dans un lien. Vous pouvez personnaliser votre WebChromeClient afin de fournir votre propre comportement pour ouvrir plusieurs fenêtres.

Pour renforcer la sécurité de votre application, il est préférable d'empêcher l'ouverture des pop-ups et des nouvelles fenêtres. Le moyen le plus sûr de mettre en œuvre ce comportement consiste à transmettre "true" à setSupportMultipleWindows(), mais pas à ignorer la méthode onCreateWindow(), dont dépend setSupportMultipleWindows(). Cette logique empêche le chargement de toute page qui utilise target="_blank" dans ses liens.