Vue d'ensemble de la Connexion et Messagerie MQTT¶
L'intégration MQTT permet à la couche WebView (JavaScript) de se connecter à un broker MQTT via le service Android natif (BleService), de publier des messages et de s'abonner/se désabonner des sujets. Toutes les interactions se font via les gestionnaires bridgeWebView.
Flux de Communication MQTT¶
┌──────────┐
│ START │
└────┬─────┘
│
▼
┌─────────────────────────┐
│ Register Callbacks │
│ - connectCallback │
│ - messageArrivedCallback│
└────┬────────────────────┘
│
▼
┌─────────────────────────┐
│ Connect to Broker │ ──────> connectMqtt({
└────┬────────────────────┘ hostname,
│ port,
│ (Async Connection) clientId
│ })
▼
┌─────────────────────────┐
│ connectCallback │
│ Called │
└────┬────────────────────┘
│
├───────────┬───────────┐
▼ ▼ ▼
Success Failed Timeout
│
▼
┌─────────────────────────┐
│ Subscribe to Topics │ ──────> mqttSubTopic({
└────┬────────────────────┘ topic,
│ qos
│ })
│
├─────────────────────────────┐
│ │
│ ▼
│ ┌─────────────────┐
│ │ Publish Message │
│ │ │
│ │ mqttPublishMsg({│
│ │ topic, │
│ │ content, │
│ │ qos │
│ │ }) │
│ └─────────────────┘
│
▼
┌─────────────────────────┐
│ Wait for Messages │
│ │
│ messageArrivedCallback │ <──── (Messages arrive)
│ fired when msg received │
└────┬────────────────────┘
│
│ (Process messages...)
│
▼
┌─────────────────────────┐
│ Unsubscribe │ ──────> mqttUnSubTopic()
└────┬────────────────────┘
│
▼
┌──────────┐
│ END │
└──────────┘
À un niveau élevé, le flux MQTT est :
- Se connecter au broker MQTT via
connectMqtt - S'abonner aux sujets via
mqttSubTopic - Recevoir des messages via le rappel JavaScript
mqttMsgArrivedCallBack - Publier des messages via
mqttPublishMsg - Se désabonner via
mqttUnSubTopicquand ce n'est plus nécessaire
En interne, la connectivité MQTT est gérée par BleService qui encapsule une instance MqttClientUtil.
Gestionnaires MQTT Exposés à JavaScript¶
Toutes les opérations MQTT sont exposées comme gestionnaires de pont enregistrés sur bridgeWebView à l'intérieur de BaseWebViewActivity :
connectMqttmqttSubTopicmqttUnSubTopicmqttPublishMsg
De plus, les messages arrivant du broker sont envoyés du natif à JavaScript via le rappel : mqttMsgArrivedCallBack
Chaque gestionnaire accepte des paramètres sous forme de chaîne JSON et retourne un objet Result encodé en JSON au rappel JavaScript.
En JS, vous utilisez généralement :
const result = JSON.parse(response);
if (result.success) {
// ...
}
1. Connexion au Broker MQTT – connectMqtt¶
Objectif : - Établir une connexion à un broker MQTT en utilisant la configuration fournie par JavaScript.
Gestionnaire de Pont¶
bridgeWebView.registerHandler("connectMqtt", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
// ...
}
});
Entrée (depuis JavaScript)¶
data: chaîne JSON représentant un objet MqttConfig.
Champs requis minimum (validés dans BaseWebViewActivity) :
- hostname – hôte / IP du broker
- port – port du broker (ex. 1883 / 8883)
- clientId – identifiant unique du client MQTT
Exemple de charge utile depuis JS :
const config = {
hostname: "mqtt.example.com",
port: 1883,
clientId: "my-client-id-123",
// Possible additional fields depending on MqttConfig:
// username, password, ssl, keepAlive, etc.
};
bridgeWebView.callHandler("connectMqtt", JSON.stringify(config), function (response) {
const result = JSON.parse(response);
if (result.success) {
console.log("MQTT connect request accepted, waiting for final callback...");
} else {
console.error("Invalid MQTT config:", result);
}
});
Logique Native (simplifiée)¶
1. Valider la charge utile¶
- Si
dataest vide → retourneResult.fail(PARAMETER_ERROR, false) - Analyser JSON en
MqttConfig mqttConfig - Vérifier les champs requis :
hostname,port,clientId
Si un champ requis est manquant ou invalide → retourne Result.fail(PARAMETER_ERROR, false)
2. Réponse immédiate à JS¶
Si la validation réussit, le natif retourne immédiatement Result.ok(true) au rappel JS appelant. La connexion réelle est effectuée de manière asynchrone dans un thread d'arrière-plan.
3. Connexion asynchrone¶
ThreadPool.getExecutor().execute(() -> { boolean b = bleService.connectMqtt(mqttConfig); ... })- Après que
bleService.connectMqtt(mqttConfig)se termine, le résultat est publié sur le thread UI.
4. Rappel de résultat final à JS¶
- En cas de succès :
bridgeWebView.callHandler("connectMqttCallBack", gson.toJson(Result.ok(true)), ...); - En cas d'échec (ex. broker inaccessible, échec d'authentification) :
bridgeWebView.callHandler("connectMqttCallBack", gson.toJson(Result.fail(MQTT_CONNECT_FAIL, false)), ...);
Comment gérer en JavaScript¶
Vous devez définir le gestionnaire connectMqttCallBack côté JS pour savoir quand la connexion a réellement réussi ou échoué :
bridgeWebView.registerHandler("connectMqttCallBack", function (data) {
const result = JSON.parse(data);
if (result.success) {
console.log("MQTT connected successfully");
// Now it's safe to subscribe and publish
} else {
console.error("MQTT connection failed:", result);
}
});
2. Abonnement aux Sujets – mqttSubTopic¶
Objectif¶
Abonner le client MQTT actuel à un sujet donné avec un niveau QoS spécifié.
Gestionnaire de Pont¶
bridgeWebView.registerHandler("mqttSubTopic", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
// ...
}
});
Entrée (depuis JavaScript)¶
dataest une chaîne JSON avec :topic– chaîne de sujet MQTT (ex."devices/abc123/status")qos– niveau QoS (0,1, ou2)
Exemple d'appel :
const payload = {
topic: "devices/abc123/status",
qos: 1,
};
bridgeWebView.callHandler("mqttSubTopic", JSON.stringify(payload), function (response) {
const result = JSON.parse(response);
if (result.success) {
console.log("Subscribed to topic successfully");
} else {
console.error("Failed to subscribe:", result);
}
});
const payload = {
topic: "devices/abc123/status",
qos: 1,
};
bridgeWebView.callHandler("mqttSubTopic", JSON.stringify(payload), function (response) {
const result = JSON.parse(response);
if (result.success) {
console.log("Subscribed to topic successfully");
} else {
console.error("Failed to subscribe:", result);
}
});
Logique Native (simplifiée)¶
- Analyser
dataenJSONObject. - Extraire
topicetqos. -
Récupérer le client MQTT :
MqttClientUtil mqttClientUtil = bleService.getMqttClientUtil(); -
Vérifier la connexion :
- Si
mqttClientUtil== null ou!mqttClientUtil.isConnected()→Result.fail(MQTT_CURRENT_NOT_CONNECTED, false)
- Si
Appel :
boolean subscribe = mqttClientUtil.subscribe(topic, qos);
subscribe == true → Result.ok(true)
- Sinon →Result.fail(FAIL, false)
Pour toute exception → Result.fail(PARAMETER_ERROR, false)
3. Désabonnement des Sujets – mqttUnSubTopic¶
Objectif¶
Se désabonner d'un sujet précédemment abonné.
Gestionnaire de Pont¶
bridgeWebView.registerHandler("mqttUnSubTopic", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
// ...
}
});
Entrée (depuis JavaScript)¶
data est une chaîne JSON avec :
- topic – sujet MQTT pour se désabonner
Exemple d'appel :
const payload = {
topic: "devices/abc123/status",
};
bridgeWebView.callHandler("mqttUnSubTopic", JSON.stringify(payload), function (response) {
const result = JSON.parse(response);
if (result.success) {
console.log("Unsubscribed from topic");
} else {
console.error("Failed to unsubscribe:", result);
}
});
Logique Native (simplifiée)¶
- Analyser le sujet depuis JSON.
- Récupérer MqttClientUtil via bleService.getMqttClientUtil().
- Si MQTT n'est pas connecté → Result.fail(MQTT_CURRENT_NOT_CONNECTED, false).
- Appel :
boolean ok = mqttClientUtil.unSubscribe(topic); - Si
ok→Result.ok(true)Sinon →Result.fail(FAIL, false) - Pour toute
exception→Result.fail(PARAMETER_ERROR, false)
4. Publication de Messages – mqttPublishMsg¶
Objectif¶
Publier un message sur un sujet MQTT spécifique avec un niveau QoS donné.
Gestionnaire de Pont¶
bridgeWebView.registerHandler("mqttPublishMsg", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
// ...
}
});
Entrée (depuis JavaScript)¶
dataest une chaîne JSON :topic– sujet MQTT sur lequel publier- content – charge utile/corps du message (chaîne)
qos– niveau QoS (0,1,2)
Exemple d'appel :
const payload = {
topic: "devices/abc123/commands",
content: JSON.stringify({ action: "reboot" }),
qos: 1,
};
bridgeWebView.callHandler("mqttPublishMsg", JSON.stringify(payload), function (response) {
const result = JSON.parse(response);
if (result.success) {
console.log("Message published");
} else {
console.error("Failed to publish:", result);
}
});
Logique Native (simplifiée)¶
- Analyser
topic,content, etqosdepuis JSON. - Récupérer
MqttClientUtilviableService.getMqttClientUtil(). - Vérifier la connexion ; si déconnecté →
Result.fail(MQTT_CURRENT_NOT_CONNECTED, false). - Publier :
boolean ok = mqttClientUtil.publish(topic, qos, content.getBytes(StandardCharsets.UTF_8));
5. Réception des Messages MQTT – mqttMsgArrivedCallBack¶
Objectif¶
Livrer les messages MQTT entrants du natif (via EventBus) à JavaScript.
Flux Natif¶
BleService (via MqttClientUtil) reçoit les messages MQTT et les publie sur un canal EventBus avec le tag EventBusEnum.MQTT_MSG_ARRIVED. BaseWebViewActivity écoute ces événements :
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(EventBusMsg message) {
// ...
} else if (message.getTagEnum() == EventBusEnum.MQTT_MSG_ARRIVED) {
bridgeWebView.callHandler("mqttMsgArrivedCallBack",
(String) message.getT(),
new CallBackFunction() {
@Override
public void onCallBack(String data) { }
});
}
// ...
}
message.getT() est censé être une représentation String de la charge utile MQTT (et éventuellement des métadonnées, selon la façon dont MqttClientUtil la formate).
Gestion en JavaScript¶
Vous devez enregistrer un gestionnaire pour mqttMsgArrivedCallBack pour recevoir et analyser les messages entrants :
bridgeWebView.registerHandler("mqttMsgArrivedCallBack", function (payload) {
// `payload` is a string coming from native.
// It might be plain text or JSON-encoded, depending on your MQTT publisher.
try {
const parsed = JSON.parse(payload);
console.log("MQTT message (parsed):", parsed);
// Handle structured message here
} catch (e) {
console.log("MQTT message (raw):", payload);
// Handle plain string payload
}
});
6. Codes d'Erreur et Gestion des Résultats¶
Les gestionnaires liés à MQTT utilisent Result.ok(...) et Result.fail(code, ...) pour encapsuler les réponses. Les codes d'erreur pertinents incluent :
MQTT_CONNECT_FAIL– la tentative de connexion au broker a échoué (configuration invalide, erreur réseau, erreur d'authentification, etc.)MQTT_CURRENT_NOT_CONNECTED– toute opération nécessitant une connexion MQTT active (s'abonner, se désabonner, publier) a été appelée alors que le client estnullou déconnecté.PARAMETER_ERROR– la charge utile de la requête est manquante des champs requis ou ne peut pas être analysée.FAIL– échec générique (ex. subscribe / publish a retournéfalse).
Côté JS, vous devriez vérifier systématiquement :
const result = JSON.parse(response);
if (!result.success) {
console.error("MQTT error:", result.code, result.message);
}
7. Flux d'Utilisation MQTT Typique (Depuis JavaScript)¶
- Configurer et Se Connecter
- Construire un objet
MqttConfig. - Appeler
connectMqttavec la configuration JSON. - Attendre connectMqttCallBack avec
success = true.
- Construire un objet
- S'Abonner aux Sujets
- Pour chaque sujet, appeler
mqttSubTopicavec{ topic, qos }.
- Pour chaque sujet, appeler
- Enregistrer le Gestionnaire de Messages
- Enregistrer
mqttMsgArrivedCallBackpour traiter les messages entrants.
- Enregistrer
- Publier des Messages
- Utiliser
mqttPublishMsgpour envoyer des commandes ou des données au broker.
- Utiliser
- Se Désabonner et Nettoyer
- Lorsque vous quittez l'écran ou n'avez plus besoin d'un sujet, appeler
mqttUnSubTopic. - La déconnexion MQTT est actuellement gérée dans la couche native (aucun gestionnaire de pont
disconnectMqttexplicite n'est exposé dansBaseWebViewActivity).
- Lorsque vous quittez l'écran ou n'avez plus besoin d'un sujet, appeler
8. Mise à Jour d'État¶
Une fois tous les gestionnaires enregistrés, dispatch({ type: "SET_BRIDGE_INITIALIZED", payload: true }) met à jour l'état de l'application pour indiquer que le pont est maintenant initialisé. Cet indicateur empêche la ré-initialisation lors des appels futurs, assurant que l'application maintient un seul point de communication entre JavaScript et WebView.
9. Résumé des Fonctions¶
La fonction setupBridge fournit une méthode organisée et sécurisée pour gérer diverses interactions basées sur Bluetooth, QR code et MQTT dans l'application. Chaque gestionnaire valide et traite les données, assurant une gestion cohérente des états et réduisant les problèmes potentiels liés à la gestion asynchrone des données. Cette structure permet une communication transparente entre WebView et l'état de l'application, permettant des échanges de données complexes et multi-sources avec un seul appel d'initialisation.
Résumé¶
La technologie BLE utilisée ici semble être :
- Central-Périphérique avec Profil GATT : L'application (centrale) scanne, se connecte et interagit avec des périphériques, récupérant les services et caractéristiques GATT.
- Intégration IoT via MQTT : Les données BLE ou les mises à jour d'état peuvent être envoyées à un serveur via MQTT, suggérant une intégration avec un écosystème IoT plus large.
- Structure d'Application Hybride : La présence de
WebViewJavascriptBridgeindique une application WebView ou hybride, permettant la fonctionnalité BLE dans un environnement multi-plateforme.
Cette configuration permettrait à une application mobile de scanner, de se connecter, d'initialiser et d'interagir avec des appareils BLE dans un contexte IoT, en utilisant potentiellement MQTT pour envoyer des données à un service cloud ou à un backend.
Cette séparation maintient la connexion MQTT et la gestion bas niveau dans le code natif, tandis que la couche WebView/JavaScript n'a besoin que d'utiliser un petit ensemble de méthodes de pont et de rappels pour intégrer MQTT dans l'IU et la logique métier.