From deec1d6faf0361569121937701e5835f78d4cd9c Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Tue, 24 Mar 2026 02:20:07 +0100
Subject: [PATCH] fix: clean force-reconnect on resume with intentionalClose flag
---
lib/services/mqtt_service.dart | 42 +++++++++++++++---------------------------
1 files changed, 15 insertions(+), 27 deletions(-)
diff --git a/lib/services/mqtt_service.dart b/lib/services/mqtt_service.dart
index 4891638..34e638c 100644
--- a/lib/services/mqtt_service.dart
+++ b/lib/services/mqtt_service.dart
@@ -516,34 +516,22 @@
case AppLifecycleState.resumed:
if (_intentionalClose) break;
_mqttLog('MQTT: app resumed, status=$_status');
- if (_status != ConnectionStatus.connected) {
- // Already knows it's disconnected — just reconnect
- connect();
- } else {
- // Thinks it's connected — verify by sending a ping command.
- // If the connection is dead, the publish will fail or we won't
- // get a pong back. Set a watchdog timer.
- _mqttLog('MQTT: sending health check...');
- _publish('pailot/control/in', {
- 'type': 'command',
- 'command': 'ping',
- 'msgId': DateTime.now().millisecondsSinceEpoch.toString(),
- 'ts': DateTime.now().millisecondsSinceEpoch,
- }, MqttQos.atLeastOnce);
- // If no pong within 3s, force reconnect
- Future.delayed(const Duration(seconds: 3), () {
- if (_status == ConnectionStatus.connected) {
- // Check if client is still actually connected
- final client = _client;
- if (client == null || client.connectionStatus?.state != MqttConnectionState.connected) {
- _mqttLog('MQTT: health check failed, reconnecting...');
- _client = null;
- _setStatus(ConnectionStatus.reconnecting);
- connect();
- }
- }
- });
+ // iOS kills TCP sockets during suspend. Always force a clean
+ // reconnect to avoid the "looks connected but dead" state.
+ final resumeClient = _client;
+ if (resumeClient != null) {
+ _intentionalClose = true; // Prevent _onDisconnected from cascading
+ resumeClient.autoReconnect = false;
+ resumeClient.disconnect();
+ _client = null;
+ _updatesSub?.cancel();
+ _updatesSub = null;
+ _intentionalClose = false;
}
+ _setStatus(ConnectionStatus.reconnecting);
+ Future.delayed(const Duration(milliseconds: 300), () {
+ if (!_intentionalClose) connect();
+ });
case AppLifecycleState.paused:
break;
default:
--
Gitblit v1.3.1