@@ -32,22 +32,32 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
32
32
operationQueue. addOperation ( operation)
33
33
}
34
34
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)
35
45
@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 ] ? ) {
37
47
guard let callbackHandle = UserDefaultsHelper . getStoredCallbackHandle ( ) ,
38
48
let _ = FlutterCallbackCache . lookupCallbackInformation ( callbackHandle)
39
49
else {
40
50
logError ( " [ \( String ( describing: self ) ) ] \( WMPError . workmanagerNotInitialized. message) " )
41
51
return
42
52
}
43
53
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 ?? ( 15 * 60 ) )
46
56
47
57
let operationQueue = OperationQueue ( )
48
58
let operation = createBackgroundOperation (
49
59
identifier: task. identifier,
50
- inputData: nil ,
60
+ inputData: inputData ,
51
61
backgroundMode: . backgroundPeriodicTask( identifier: identifier)
52
62
)
53
63
@@ -57,6 +67,13 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
57
67
operationQueue. addOperation ( operation)
58
68
}
59
69
70
+ /// Starts a one-off background task with the specified input data.
71
+ ///
72
+ /// - Parameters:
73
+ /// - identifier: Task identifier
74
+ /// - taskIdentifier: iOS background task identifier for lifecycle management
75
+ /// - inputData: Input data to pass to the Flutter task
76
+ /// - delaySeconds: Delay before task execution
60
77
@available ( iOS 13 . 0 , * )
61
78
public static func startOneOffTask( identifier: String , taskIdentifier: UIBackgroundTaskIdentifier , inputData: [ String : Any ] ? , delaySeconds: Int64 ) {
62
79
let operationQueue = OperationQueue ( )
@@ -70,38 +87,67 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
70
87
operationQueue. addOperation ( operation)
71
88
}
72
89
90
+ /// Registers a periodic background task with iOS BGTaskScheduler.
91
+ ///
92
+ /// This method must be called during app initialization (typically in AppDelegate)
93
+ /// to register the task identifier with iOS. The actual task scheduling with inputData
94
+ /// happens later when called from the Dart/Flutter side.
95
+ ///
96
+ /// - Parameters:
97
+ /// - identifier: Unique task identifier that matches the one used in Dart
98
+ /// - earliestBeginInSeconds: Optional delay before scheduling next occurrence
99
+ ///
100
+ /// - Note: This registers the task handler only. Use Workmanager.registerPeriodicTask()
101
+ /// from Dart to actually schedule the task with inputData.
73
102
@objc
74
- public static func registerPeriodicTask( withIdentifier identifier: String , frequency : NSNumber ? ) {
103
+ public static func registerPeriodicTask( withIdentifier identifier: String , earliestBeginInSeconds : NSNumber ? = nil ) {
75
104
if #available( iOS 13 . 0 , * ) {
76
- var frequencyInSeconds : Double ?
77
- if let frequencyValue = frequency {
78
- frequencyInSeconds = frequencyValue. doubleValue
79
- }
80
-
81
105
BGTaskScheduler . shared. register (
82
106
forTaskWithIdentifier: identifier,
83
107
using: nil
84
108
) { task in
85
109
if let task = task as? BGAppRefreshTask {
86
- handlePeriodicTask ( identifier: identifier, task: task, earliestBeginInSeconds: frequencyInSeconds)
110
+ // Retrieve the stored inputData for this periodic task
111
+ let storedInputData = UserDefaultsHelper . getStoredPeriodicTaskInputData ( forTaskIdentifier: task. identifier)
112
+ handlePeriodicTask ( identifier: identifier, task: task, earliestBeginInSeconds: earliestBeginInSeconds, inputData: storedInputData)
87
113
}
88
114
}
89
115
}
90
116
}
91
117
118
+ /// Registers a periodic background task with iOS BGTaskScheduler.
119
+ ///
120
+ /// - Parameters:
121
+ /// - identifier: Unique task identifier that matches the one used in Dart
122
+ /// - frequency: Frequency hint in seconds (deprecated, use earliestBeginInSeconds instead)
123
+ ///
124
+ /// - Note: Deprecated. Use registerPeriodicTask(withIdentifier:frequency:earliestBeginInSeconds:) instead.
125
+ @available ( * , deprecated, message: " Use registerPeriodicTask(withIdentifier:earliestBeginInSeconds:) instead " )
92
126
@objc
127
+ public static func registerPeriodicTask( withIdentifier identifier: String , frequency: NSNumber ? ) {
128
+ registerPeriodicTask ( withIdentifier: identifier, earliestBeginInSeconds: frequency)
129
+ }
130
+
93
131
@available ( iOS 13 . 0 , * )
94
- private static func schedulePeriodicTask( taskIdentifier identifier: String , earliestBeginInSeconds begin: Double ) {
132
+ private static func schedulePeriodicTask( taskIdentifier identifier: String , earliestBeginInSeconds begin: Double ? ) {
95
133
let request = BGAppRefreshTaskRequest ( identifier: identifier)
96
- request. earliestBeginDate = Date ( timeIntervalSinceNow: begin)
134
+ if let begin = begin {
135
+ request. earliestBeginDate = Date ( timeIntervalSinceNow: begin)
136
+ }
97
137
do {
98
138
try BGTaskScheduler . shared. submit ( request)
99
- logInfo ( " BGAppRefreshTask submitted \( identifier) earliestBeginInSeconds: \( begin) " )
139
+ logInfo ( " BGAppRefreshTask submitted \( identifier) earliestBeginInSeconds: \( String ( describing : begin) ) " )
100
140
} catch {
101
141
logInfo ( " Could not schedule BGAppRefreshTask \( error. localizedDescription) " )
102
142
}
103
143
}
104
144
145
+ /// Registers a background processing task with iOS BGTaskScheduler.
146
+ ///
147
+ /// This method must be called during app initialization (typically in AppDelegate)
148
+ /// to register the task identifier with iOS for background processing tasks.
149
+ ///
150
+ /// - Parameter identifier: Unique task identifier that matches the one used in Dart
105
151
@objc
106
152
public static func registerBGProcessingTask( withIdentifier identifier: String ) {
107
153
if #available( iOS 13 . 0 , * ) {
@@ -140,6 +186,12 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
140
186
141
187
// MARK: - FlutterPlugin conformance
142
188
189
+ /// Sets the plugin registrant callback for background task execution.
190
+ ///
191
+ /// This callback is used to register additional plugins when background tasks
192
+ /// run in a separate Flutter engine instance.
193
+ ///
194
+ /// - Parameter callback: The callback to register plugins in the background engine
143
195
@objc
144
196
public static func setPluginRegistrantCallback( _ callback: @escaping FlutterPluginRegistrantCallback ) {
145
197
flutterPluginRegistrantCallback = callback
@@ -191,6 +243,13 @@ public class WorkmanagerPlugin: FlutterPluginAppLifeCycleDelegate, FlutterPlugin
191
243
192
244
executeIfSupportedVoid ( completion: completion, feature: " PeriodicTask " ) {
193
245
let initialDelaySeconds = Double ( request. initialDelaySeconds ?? 0 )
246
+
247
+ // Store the inputData for later retrieval when the task executes
248
+ UserDefaultsHelper . storePeriodicTaskInputData (
249
+ request. inputData as? [ String : Any ] ,
250
+ forTaskIdentifier: request. uniqueName
251
+ )
252
+
194
253
WorkmanagerPlugin . schedulePeriodicTask (
195
254
taskIdentifier: request. uniqueName,
196
255
earliestBeginInSeconds: initialDelaySeconds
0 commit comments