@@ -32,31 +32,55 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
3232 operationQueue. addOperation ( operation)
3333 }
3434
35+ /// Handles execution of a periodic background task.
36+ ///
37+ /// This method is called by iOS when a BGAppRefreshTask is triggered.
38+ /// It retrieves stored inputData and executes the Flutter task.
39+ ///
40+ /// - Parameters:
41+ /// - identifier: Task identifier
42+ /// - task: The BGAppRefreshTask instance from iOS
43+ /// - earliestBeginInSeconds: Optional delay before scheduling next occurrence
44+ /// - inputData: Input data passed from the Dart side (may be nil)
3545 @available ( iOS 13 . 0 , * )
36- public static func handlePeriodicTask( identifier: String , task: BGAppRefreshTask , earliestBeginInSeconds: Double ? ) {
46+ public static func handlePeriodicTask( identifier: String , task: BGAppRefreshTask , earliestBeginInSeconds: NSNumber ? , inputData : [ String : Any ] ? ) {
3747 guard let callbackHandle = UserDefaultsHelper . getStoredCallbackHandle ( ) ,
3848 let _ = FlutterCallbackCache . lookupCallbackInformation ( callbackHandle)
3949 else {
4050 logError ( " [ \( String ( describing: self ) ) ] \( WMPError . workmanagerNotInitialized. message) " )
4151 return
4252 }
4353
44- // If frequency is not provided it will default to 15 minutes
45- schedulePeriodicTask ( taskIdentifier: task. identifier, earliestBeginInSeconds: earliestBeginInSeconds ?? ( 15 * 60 ) )
54+ // Schedule the next occurrence (iOS will determine actual timing based on usage patterns)
55+ schedulePeriodicTask ( taskIdentifier: task. identifier, earliestBeginInSeconds: earliestBeginInSeconds? . doubleValue )
4656
47- let operationQueue = OperationQueue ( )
48- let operation = createBackgroundOperation (
49- identifier : task . identifier,
50- inputData: nil ,
51- backgroundMode : . backgroundPeriodicTask ( identifier : identifier )
57+ // Execute the Flutter task directly
58+ let worker = BackgroundWorker (
59+ mode : . backgroundPeriodicTask ( identifier: identifier ) ,
60+ inputData: inputData ,
61+ flutterPluginRegistrantCallback : flutterPluginRegistrantCallback
5262 )
5363
54- task. expirationHandler = { operation. cancel ( ) }
55- operation. completionBlock = { task. setTaskCompleted ( success: !operation. isCancelled) }
64+ // Set up expiration handler
65+ task. expirationHandler = {
66+ logInfo ( " BGAppRefreshTask expired: \( identifier) " )
67+ }
5668
57- operationQueue. addOperation ( operation)
69+ // Execute on main thread (required for Flutter)
70+ DispatchQueue . main. async {
71+ worker. performBackgroundRequest { result in
72+ task. setTaskCompleted ( success: result == . newData)
73+ }
74+ }
5875 }
5976
77+ /// Starts a one-off background task with the specified input data.
78+ ///
79+ /// - Parameters:
80+ /// - identifier: Task identifier
81+ /// - taskIdentifier: iOS background task identifier for lifecycle management
82+ /// - inputData: Input data to pass to the Flutter task
83+ /// - delaySeconds: Delay before task execution
6084 @available ( iOS 13 . 0 , * )
6185 public static func startOneOffTask( identifier: String , taskIdentifier: UIBackgroundTaskIdentifier , inputData: [ String : Any ] ? , delaySeconds: Int64 ) {
6286 let operationQueue = OperationQueue ( )
@@ -70,38 +94,67 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
7094 operationQueue. addOperation ( operation)
7195 }
7296
97+ /// Registers a periodic background task with iOS BGTaskScheduler.
98+ ///
99+ /// This method must be called during app initialization (typically in AppDelegate)
100+ /// to register the task identifier with iOS. The actual task scheduling with inputData
101+ /// happens later when called from the Dart/Flutter side.
102+ ///
103+ /// - Parameters:
104+ /// - identifier: Unique task identifier that matches the one used in Dart
105+ /// - earliestBeginInSeconds: Optional delay before scheduling next occurrence
106+ ///
107+ /// - Note: This registers the task handler only. Use Workmanager.registerPeriodicTask()
108+ /// from Dart to actually schedule the task with inputData.
73109 @objc
74- public static func registerPeriodicTask( withIdentifier identifier: String , frequency : NSNumber ? ) {
110+ public static func registerPeriodicTask( withIdentifier identifier: String , earliestBeginInSeconds : NSNumber ? = nil ) {
75111 if #available( iOS 13 . 0 , * ) {
76- var frequencyInSeconds : Double ?
77- if let frequencyValue = frequency {
78- frequencyInSeconds = frequencyValue. doubleValue
79- }
80-
81112 BGTaskScheduler . shared. register (
82113 forTaskWithIdentifier: identifier,
83114 using: nil
84115 ) { task in
85116 if let task = task as? BGAppRefreshTask {
86- handlePeriodicTask ( identifier: identifier, task: task, earliestBeginInSeconds: frequencyInSeconds)
117+ // Retrieve the stored inputData for this periodic task
118+ let storedInputData = UserDefaultsHelper . getStoredPeriodicTaskInputData ( forTaskIdentifier: task. identifier)
119+ handlePeriodicTask ( identifier: identifier, task: task, earliestBeginInSeconds: earliestBeginInSeconds, inputData: storedInputData)
87120 }
88121 }
89122 }
90123 }
91124
125+ /// Registers a periodic background task with iOS BGTaskScheduler.
126+ ///
127+ /// - Parameters:
128+ /// - identifier: Unique task identifier that matches the one used in Dart
129+ /// - frequency: Frequency hint in seconds (deprecated, use earliestBeginInSeconds instead)
130+ ///
131+ /// - Note: Deprecated. Use registerPeriodicTask(withIdentifier:frequency:earliestBeginInSeconds:) instead.
132+ @available ( * , deprecated, message: " Use registerPeriodicTask(withIdentifier:earliestBeginInSeconds:) instead " )
92133 @objc
134+ public static func registerPeriodicTask( withIdentifier identifier: String , frequency: NSNumber ? ) {
135+ registerPeriodicTask ( withIdentifier: identifier, earliestBeginInSeconds: frequency)
136+ }
137+
93138 @available ( iOS 13 . 0 , * )
94- private static func schedulePeriodicTask( taskIdentifier identifier: String , earliestBeginInSeconds begin: Double ) {
139+ private static func schedulePeriodicTask( taskIdentifier identifier: String , earliestBeginInSeconds begin: Double ? ) {
95140 let request = BGAppRefreshTaskRequest ( identifier: identifier)
96- request. earliestBeginDate = Date ( timeIntervalSinceNow: begin)
141+ if let begin = begin {
142+ request. earliestBeginDate = Date ( timeIntervalSinceNow: begin)
143+ }
97144 do {
98145 try BGTaskScheduler . shared. submit ( request)
99- logInfo ( " BGAppRefreshTask submitted \( identifier) earliestBeginInSeconds: \( begin) " )
146+ logInfo ( " BGAppRefreshTask submitted \( identifier) earliestBeginInSeconds: \( String ( describing : begin) ) " )
100147 } catch {
101148 logInfo ( " Could not schedule BGAppRefreshTask \( error. localizedDescription) " )
102149 }
103150 }
104151
152+ /// Registers a background processing task with iOS BGTaskScheduler.
153+ ///
154+ /// This method must be called during app initialization (typically in AppDelegate)
155+ /// to register the task identifier with iOS for background processing tasks.
156+ ///
157+ /// - Parameter identifier: Unique task identifier that matches the one used in Dart
105158 @objc
106159 public static func registerBGProcessingTask( withIdentifier identifier: String ) {
107160 if #available( iOS 13 . 0 , * ) {
@@ -140,6 +193,12 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
140193
141194 // MARK: - FlutterPlugin conformance
142195
196+ /// Sets the plugin registrant callback for background task execution.
197+ ///
198+ /// This callback is used to register additional plugins when background tasks
199+ /// run in a separate Flutter engine instance.
200+ ///
201+ /// - Parameter callback: The callback to register plugins in the background engine
143202 @objc
144203 public static func setPluginRegistrantCallback( _ callback: @escaping FlutterPluginRegistrantCallback ) {
145204 flutterPluginRegistrantCallback = callback
@@ -191,6 +250,13 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
191250
192251 executeIfSupportedVoid ( completion: completion, feature: " PeriodicTask " ) {
193252 let initialDelaySeconds = Double ( request. initialDelaySeconds ?? 0 )
253+
254+ // Store the inputData for later retrieval when the task executes
255+ UserDefaultsHelper . storePeriodicTaskInputData (
256+ request. inputData as? [ String : Any ] ,
257+ forTaskIdentifier: request. uniqueName
258+ )
259+
194260 WorkmanagerPlugin . schedulePeriodicTask (
195261 taskIdentifier: request. uniqueName,
196262 earliestBeginInSeconds: initialDelaySeconds
0 commit comments