Aller au contenu

Initialisation WebView

1. « JavaScript est activé. »

WebView a javaScriptEnabled = true (Android) ou équivalent, donc le code JS à l'intérieur de la page chargée peut réellement s'exécuter.

Sans cela, les balises <script> et toute logique JS dans votre HTML seraient complètement ignorées par WebView.

L'activation de JS est nécessaire pour :

  • Appeler des fonctions de pont natif depuis JS.
  • Gérer les événements de clic, les mises à jour dynamiques de l'IU, les appels AJAX/fetch, etc.

Point de sécurité :

  • N'activez JS que pour les pages auxquelles vous faites confiance ou que vous contrôlez (ex. le propre HTML de votre application, pas des URLs non fiables arbitraires).
  • Combinez cela avec d'autres restrictions (ex. chargement d'URL restreint, politiques de sécurité du contenu).

2. « Un WebViewClient/WebChromeClient sécurisé est attaché. »

WebViewClient :

  • Contrôle la façon dont les URLs sont chargées (dans l'application vs le navigateur externe).
  • Permet d'intercepter et de valider la navigation (ex. bloquer les domaines inconnus, les liens profonds).
  • Idéal pour appliquer des règles comme « autoriser uniquement https://my-app-domain.com »

WebChromeClient :

  • Gère les fonctionnalités avancées de type navigateur :
    • Dialogues JavaScript (alert, confirm, prompt)
    • Journaux de console
    • Permissions (caméra, géolocalisation, etc.)
  • Vous donne des crochets pour approuver/refuser ce que JS essaie de faire.

  • « Sécurisé » signifie ici que vous n'utilisez pas simplement le comportement par défaut :

  • Vous remplacez les méthodes pour :
    • Valider les URLs cibles avant le chargement.
    • Empêcher le contenu mixte ou le HTTP en clair si non nécessaire.
    • Contrôler l'accès aux fichiers, à la caméra ou d'autres fonctionnalités sensibles.

Vous désactivez ou limitez les fonctionnalités dangereuses (ex. accès arbitraire aux fichiers, accès universel depuis les URLs de fichiers, etc.) sauf si explicitement requis.

3. « Tous les gestionnaires de pont sont enregistrés lors de l'initialisation. »

Votre pont natif expose des « gestionnaires » spécifiques (endpoints) que JS peut appeler, ex. :

  • takePhoto
  • getUserToken
  • openSettings

« Enregistrés lors de l'initialisation » signifie :

  • Dès que WebView (ou le module de pont) est créé, vous appelez quelque chose comme :
    • bridge.registerHandler("takePhoto", handlerFunction)
  • Au moment où la page finit de charger, tous les gestionnaires attendus existent.

Pourquoi c'est important :

  • Évite les conditions de course où JS appelle un gestionnaire qui n'est pas encore enregistré → erreurs comme « gestionnaire introuvable ».
  • Fournit un contrat clair entre JS et le natif :
  • L'ensemble des API disponibles est connu à l'avance.
  • Vous pouvez les documenter et les versionner.

Avantage sécurité :

  • Vous enregistrez uniquement ce que vous souhaitez exposer explicitement.
  • Vous n'ouvrez pas accidentellement des méthodes natives aléatoires à JS.
  • Vous pouvez ajouter des vérifications d'autorisation/permission à l'intérieur de chaque gestionnaire.

4. « JS peut appeler des méthodes natives en utilisant window.bridge.callHandler(...). »

C'est la surface API que JS voit pour communiquer avec le code natif. Forme d'appel typique :

window.bridge.callHandler("takePhoto", { quality: "high" }, function (response) { /* handle result */ });

En coulisses :

  • callHandler regroupe le nom du gestionnaire + les données dans un message.
  • Envoie le message à travers le pont JS–natif (via addJavascriptInterface, postMessage, ou des schémas d'URL personnalisés, selon votre implémentation).
  • Le code natif le reçoit, recherche le gestionnaire enregistré, l'exécute, puis envoie une réponse en retour, ce qui déclenche le rappel JS.

Avantages de conception :

  • Point d'entrée unique de JS vers natif, au lieu d'exposer de nombreux globaux aléatoires.
  • Facile à journaliser, auditer et valider :
  • Vous pouvez journaliser chaque appel callHandler et ses arguments côté natif.
  • Prend bien en charge les opérations asynchrones : le natif peut se terminer plus tard puis invoquer le rappel JS avec succès/erreur.

Enregistrement des Gestionnaires de Pont

Les gestionnaires sont enregistrés comme suit :

bridgeWebView.registerHandler("mqttConnect", new BridgeHandler() {
    @Override
    public void handler(String data, CallBackFunction function) {
        // native code
    }
});

Ce que fait cette ligne conceptuellement

  • Enregistre une API de pont nommée

    • "mqttConnect" est le nom du gestionnaire (le nom de l'API que JS appellera).
    • Vous indiquez au pont : "Quand JS appelle mqttConnect, exécuter ce code Java."
  • Connecte le monde JS → la logique MQTT native :

    • Ce gestionnaire est destiné à la logique de connexion MQTT (ex. connexion à un broker, authentification, etc.).
    • Tout le travail lourd (sockets, identifiants, nouvelles tentatives, etc.) reste dans le code natif, pas dans JS.

Scan et Connexion à un Appareil BLE

Cet extrait montre comment le code JavaScript WebView communique avec la couche native (Android/iOS) via bridgeWebView pour :

  1. Enregistrer des rappels pour les événements BLE
  2. Démarrer le scan des appareils BLE
  3. Se connecter à un appareil en utilisant son adresse MAC
// Step 1: Register callbacks
bridgeWebView.registerHandler("findBleDeviceCallBack", function(data) {
  const device = JSON.parse(data);
  console.log("Found:", device.name, device.macAddress);
});

bridgeWebView.registerHandler("bleConnectSuccessCallBack", function(macAddress) {
  console.log("Connected to:", macAddress);
});

// Step 2: Start scanning
bridgeWebView.callHandler("startBleScan", "", function(response) {
  const result = JSON.parse(response);
  if (result.success) {
    console.log("Scanning started...");
  }
});

// Step 3: Connect to device (when you find the one you want)
setTimeout(() => {
  bridgeWebView.callHandler("connBleByMacAddress", "AA:BB:CC:DD:EE:FF", function(response) {
    const result = JSON.parse(response);
    if (result.success) {
      console.log("Connecting...");
    }
  });
}, 5000);

Vue d'ensemble

  • bridgeWebView est l'objet de pont JavaScript–natif exposé dans WebView.
  • registerHandler(name, callback) enregistre une fonction JavaScript que l'application native peut appeler.
  • callHandler(name, data, callback) appelle une fonction native et reçoit optionnellement une réponse asynchrone.

Le flux général est :

  1. Le côté JS enregistre des gestionnaires pour que le code natif puisse notifier la page web.
  2. JS indique au code natif de commencer le scan des appareils BLE.
  3. Lorsqu'un appareil est trouvé, le natif rappelle JS.
  4. JS décide à quel appareil se connecter et appelle la fonction native « connect ».

Étape 1 : Enregistrement des Rappels du Natif vers JS

findBleDeviceCallBack

bridgeWebView.registerHandler("findBleDeviceCallBack", function(data) {
  const device = JSON.parse(data);
  console.log("Found:", device.name, device.macAddress);
});
  • Objectif : Ce gestionnaire est déclenché par la couche native chaque fois qu'un appareil BLE est découvert lors d'un scan.
  • Paramètres :

    • data : une chaîne JSON envoyée depuis le code natif. Elle est censée représenter un objet appareil, par exemple :
      {
          "name": "My BLE Device",
          "macAddress": "AA:BB:CC:DD:EE:FF"
      }
      
  • Logique :

  • JSON.parse(data) convertit la chaîne JSON en objet JavaScript.

  • device.name et device.macAddress sont lus depuis l'objet analysé.
  • Les informations sur l'appareil sont journalisées :
console.log("Found:", device.name, device.macAddress);
  • Comment l'utiliser :

    • Vous pouvez ensuite remplacer le console.log par des mises à jour de l'IU, ex. ajouter l'appareil à une liste pour que l'utilisateur le sélectionne.

bleConnectSuccessCallBack

bridgeWebView.registerHandler("bleConnectSuccessCallBack", function(macAddress) {
  console.log("Connected to:", macAddress);
});
  • Objectif : Notifie le côté JS qu'une connexion BLE a été établie avec succès.
  • Paramètres :

    • macAddress : une chaîne simple contenant l'adresse MAC de l'appareil connecté.
  • Logique :

    • Journalise l'adresse MAC de l'appareil connecté avec succès :
      console.log("Connected to:", macAddress);
      
  • Comment l'utiliser :

    • C'est un bon endroit pour mettre à jour l'IU vers l'état « Connecté » ou activer des fonctionnalités qui nécessitent une connexion BLE active.

Étape 2 : Démarrage du Scan BLE

bridgeWebView.callHandler("startBleScan", "", function(response) {
  const result = JSON.parse(response);
  if (result.success) {
    console.log("Scanning started...");
  }
});
  • Objectif : Demande à la couche native de commencer le scan des appareils BLE.
  • Arguments :

    • Premier argument : "startBleScan" — le nom de la méthode native.
    • Deuxième argument : "" — une chaîne vide ; aucun paramètre supplémentaire n'est nécessaire pour cet appel.
    • Troisième argument : fonction de rappel pour gérer la réponse native.
  • Gestion de la réponse :

    • response est censée être une chaîne JSON, ex. :
      { "success": true }
      
  • Elle est analysée en objet JavaScript :

    const result = JSON.parse(response);
    

  • Si result.success est true, le scan a démarré avec succès :

    if (result.success) {
      console.log("Scanning started...");
    }
    

  • Flux :

    • Après le démarrage du scan, le côté natif commencera généralement à appeler findBleDeviceCallBack chaque fois qu'il découvrira des appareils.

Étape 3 : Connexion à un Appareil par Adresse MAC

setTimeout(() => {
  bridgeWebView.callHandler("connBleByMacAddress", "AA:BB:CC:DD:EE:FF", function(response) {
    const result = JSON.parse(response);
    if (result.success) {
      console.log("Connecting...");
    }
  });
}, 5000);
  • Objectif : Se connecte à un appareil BLE spécifique en utilisant son adresse MAC.
  • setTimeout :

    • setTimeout(..., 5000); retarde cet appel de 5 secondes.
    • Cela simule : « attendre un certain temps pendant le scan et la découverte des appareils, puis essayer de se connecter ».
    • Dans une vraie application, vous appelleriez probablement ceci après que l'utilisateur sélectionne un appareil dans une liste (au lieu d'utiliser un délai fixe).

Arguments de callHandler :

  • "connBleByMacAddress" : la méthode native responsable de la connexion à un appareil.
  • "AA:BB:CC:DD:EE:FF" : l'adresse MAC de l'appareil cible (espace réservé ; doit être remplacé par l'adresse MAC réelle de l'appareil provenant de findBleDeviceCallBack ou de la sélection de l'utilisateur).
  • function(response) { ... } : rappel qui gère la réponse native.

Gestion de la réponse : - response est censée être une chaîne JSON, ex. :

{ "success": true }

  • Elle est analysée :

    const result = JSON.parse(response);
    

  • Si result.success est true, il journalise :

    console.log("Connecting...");
    

Après l'établissement réel de la connexion, le côté natif doit déclencher le gestionnaire bleConnectSuccessCallBack enregistré à l'Étape 1.

Résumé du Flux de Bout en Bout

  1. Enregistrer les rappels

    • findBleDeviceCallBack : appelé par le natif lorsqu'un appareil est trouvé.
    • bleConnectSuccessCallBack : appelé par le natif lorsqu'une connexion réussit.
  2. Démarrer le scan

    • JS appelle startBleScan.
    • Le natif commence le scan et retourne { success: true } si réussi.
    • Au fur et à mesure que les appareils sont trouvés, le natif appelle répétitivement findBleDeviceCallBack avec les données de l'appareil.
  3. Sélectionner et se connecter

    • JS décide à quel appareil se connecter (dans l'exemple : une adresse MAC codée en dur après 5 secondes).
    • JS appelle connBleByMacAddress avec l'adresse MAC choisie.
    • Le natif tente une connexion et répond avec { success: true } si le processus de connexion démarre correctement.
    • Une fois entièrement connecté, le natif déclenche bleConnectSuccessCallBack avec l'adresse MAC de l'appareil. Vous pouvez adapter les journaux aux mises à jour de l'IU (affichage des appareils dans une liste, affichage de l'état de connexion, etc.) et ajouter la gestion des erreurs en vérifiant result.success === false et en affichant des messages appropriés.