From 0c4eb09af2d52566cdfdbfaeb9c1ad789ecf9045 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Wed, 15 Apr 2026 13:51:51 +0200 Subject: [PATCH] fix(connectivity_plus): guard eventSink against FlutterEngine teardown on iOS NWPathMonitor can fire a connectivity update while the app is in the background, after the FlutterEngine's shell has been torn down. The DispatchQueue.main.async block then invokes the stale FlutterEventSink, which calls -[FlutterEngine sendOnChannel:] and hits an NSAssertion at FlutterEngine.mm:1315, aborting the process with SIGABRT. Guard the main-queue emission with [weak self], a local eventSink copy, and a UIApplication.applicationState != .background check so that pending updates are dropped instead of propagated into a dead engine. The next onListen / check call after foregrounding will resync state. --- .../connectivity_plus/ConnectivityPlusPlugin.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift index b5d1211508..56d4555b10 100644 --- a/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift +++ b/packages/connectivity_plus/connectivity_plus/ios/connectivity_plus/Sources/connectivity_plus/ConnectivityPlusPlugin.swift @@ -3,6 +3,7 @@ // be found in the LICENSE file. import Flutter +import UIKit public class ConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { private let connectivityProvider: ConnectivityProvider @@ -79,8 +80,15 @@ public class ConnectivityPlusPlugin: NSObject, FlutterPlugin, FlutterStreamHandl } private func connectivityUpdateHandler(connectivityTypes: [ConnectivityType]) { - DispatchQueue.main.async { - self.eventSink?(self.statusFrom(connectivityTypes: connectivityTypes)) + DispatchQueue.main.async { [weak self] in + guard let self = self, let eventSink = self.eventSink else { return } + // NWPathMonitor can fire while the app is in the background, after the + // FlutterEngine's shell has been torn down. Calling eventSink in that + // state triggers an NSAssertion in -[FlutterEngine sendOnChannel:] and + // crashes the app with SIGABRT. Skip the emission until the app is + // foregrounded again; the next onListen / check call will resync state. + guard UIApplication.shared.applicationState != .background else { return } + eventSink(self.statusFrom(connectivityTypes: connectivityTypes)) } }