From c85d4874a631db4ab6e2d84310e079df10db55cd Mon Sep 17 00:00:00 2001 From: Vaibhav Pandey Date: Fri, 25 Sep 2026 18:43:25 +0530 Subject: [PATCH] fix(ios): replace sleep(5) in applicationWillTerminate with bounded wait --- .../SwiftFlutterForegroundTaskPlugin.swift | 10 +++++++--- .../service/BackgroundService.swift | 12 ++++++++---- .../service/ForegroundTask.swift | 11 ++++++++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/ios/flutter_foreground_task/Sources/flutter_foreground_task/SwiftFlutterForegroundTaskPlugin.swift b/ios/flutter_foreground_task/Sources/flutter_foreground_task/SwiftFlutterForegroundTaskPlugin.swift index 33046730..c0484616 100644 --- a/ios/flutter_foreground_task/Sources/flutter_foreground_task/SwiftFlutterForegroundTaskPlugin.swift +++ b/ios/flutter_foreground_task/Sources/flutter_foreground_task/SwiftFlutterForegroundTaskPlugin.swift @@ -120,10 +120,14 @@ public class SwiftFlutterForegroundTaskPlugin: NSObject, FlutterPlugin { } BackgroundServiceStatus.setData(action: BackgroundServiceAction.APP_TERMINATE) - BackgroundService.sharedInstance.run() + var isDestroyed = false + BackgroundService.sharedInstance.run(onDestroyed: { isDestroyed = true }) - // Chance to handle onDestroy before app terminates - sleep(5) + // Wait for onDestroy (max 2s); spin run loop so its reply is served. System allows ~5s total. + let deadline = Date().addingTimeInterval(2) + while !isDestroyed && Date() < deadline { + RunLoop.current.run(mode: .default, before: deadline) + } } // ================= Service Delegate ================= diff --git a/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/BackgroundService.swift b/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/BackgroundService.swift index 4029ad80..7989354d 100644 --- a/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/BackgroundService.swift +++ b/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/BackgroundService.swift @@ -63,7 +63,7 @@ class BackgroundService: NSObject { super.init() } - func run() { + func run(onDestroyed: @escaping () -> Void = {}) { backgroundServiceStatus = BackgroundServiceStatus.getData() notificationOptions = NotificationOptions.getData() notificationContent = NotificationContent.getData() @@ -93,7 +93,7 @@ class BackgroundService: NSObject { } break case .API_STOP, .APP_TERMINATE: - destroyForegroundTask() + destroyForegroundTask(onDestroyed: onDestroyed) removeAllNotification() isRunningService = false break @@ -199,8 +199,12 @@ class BackgroundService: NSObject { foregroundTask?.update(taskEventAction: currForegroundTaskOptions.eventAction) } - private func destroyForegroundTask() { - foregroundTask?.destroy() + private func destroyForegroundTask(onDestroyed: @escaping () -> Void = {}) { + if let foregroundTask = foregroundTask { + foregroundTask.destroy(onDestroyed: onDestroyed) + } else { + onDestroyed() + } foregroundTask = nil } } diff --git a/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/ForegroundTask.swift b/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/ForegroundTask.swift index 20c5b585..0e5ba9ab 100644 --- a/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/ForegroundTask.swift +++ b/ios/flutter_foreground_task/Sources/flutter_foreground_task/service/ForegroundTask.swift @@ -155,7 +155,11 @@ class ForegroundTask { } } - func destroy() { + func destroy(onDestroyed: @escaping () -> Void = {}) { + if isDestroyed { + onDestroyed() + return + } runIfNotDestroyed { stopRepeatTask() @@ -164,10 +168,15 @@ class ForegroundTask { taskLifecycleListener.onEngineWillDestroy() flutterEngine?.destroyContext() flutterEngine = nil + onDestroyed() } else { + if backgroundChannel == nil { + onDestroyed() + } backgroundChannel?.invokeMethod(ACTION_TASK_DESTROY, arguments: nil) { _ in self.flutterEngine?.destroyContext() self.flutterEngine = nil + onDestroyed() } taskLifecycleListener.onTaskDestroy() taskLifecycleListener.onEngineWillDestroy()