flutter_workmanager
                                
                                
                                
                                    flutter_workmanager copied to clipboard
                            
                            
                            
                        feat!: iOS major enhancements BGAppRefreshTask, BGProcessingTask, beginBackgroundTask, printScheduledTasks
Closes #295 Closes #450 Closes #497
Due to iOS side of this plugin falling behind Android it was necessary to do a major overhaul on iOS side. In summary the new changes are:
- iOS now supports one off immediate tasks 
Workmanager.registerOneOffTaskwhich now uses iOSbeginBackgroundTaskinstead of previousBGAppRefreshTasksolution, migration guide is created for this. The reason to not use BGAppRefreshTask is to make it in line with Android side design and tackle some items discussed in #295 - New periodic tasks 
Workmanager.registerPeriodicTaskwhich uses iOSBGAppRefreshTask - New long running tasks 
Workmanager.registerProcessingTaskusing iOSBGProcessingTask, which was previously being done byregisterOneOffTask. If or when Android side feature request #236 is done that should be linked toWorkmanager.registerProcessingTaskto have same feature on both platforms - New 
Workmanager.checkBackgroundRefreshPermissionto check Background App Refresh permission. On iOS user can disableBackground App Refreshpermission anytime, hence background tasks can only run if user has granted the permission. WithWorkmanager.checkBackgroundRefreshPermissionyou can check whether background app refresh is enabled Workmanager.printScheduledTasksto print details of scheduled tasks to console. To be used during development/debugging. This will to some extent give developers some confidence that tasks are really scheduled and iOS will trigger at some point in the future- Example App has been updated to use the new methods. A new button is added to make it easy to check the status of tasks, it prints scheduled task details to console and displays the saved shared preferences values on screen
 - iOS documentation updates to minimize confusion and iOS understanding issues. Readme, iOS setup and API level docs are updated
 - A migration section is created for breaking changes
 
Migration
BREAKING CHANGE: This PR has some breaking changes for iOS:
- Workmanager.registerOneOffTask was previously using iOS BGProcessingTask, now it will be an immediate run task which will continue in the background if user leaves the App. Since the previous solution meant the one off task will only run if the device is idle and as often experienced only when device is charging, in practice it means somewhere at night, or not at all during that day, because BGProcessingTask is meant for long running tasks. The new solution makes it more in line with Android except it does not support initialDelay
 - If you need the old behavior you can use the new iOS only method 
Workmanager.registerProcessingTask:- Replace 
Workmanager().registerOneOffTaskwithWorkmanager().registerProcessingTaskin your App - Replace 
WorkmanagerPlugin.registerTaskwithWorkmanagerPlugin.registerBGProcessingTaskinAppDelegate.swift 
 - Replace 
 - Workmanager.registerOneOffTask does not support initialDelay
 - Workmanager.registerOneOffTask now supports inputData which was always returning null in the previous solution
 - Workmanager.registerOneOffTask now does NOT require 
WorkmanagerPlugin.registerTaskcall inAppDelegate.swifthence remove the call 
I am not a native iOS developer but tried to address my own needs after not finding any solution and waiting for too long, it will help me if you guys test and raise any issues even if this PR doesn't get merged, i will try to maintain my branch https://github.com/absar/flutter_workmanager/tree/ios-bg-tasks-enh-final
Shoutout to Lars Huth/xunreal75 for his attempt in 2022, his work helped a lot during this PR
@absar Impressive amount of work.
Something initial - the permission check and APIs should be done with permission_handler or any other plugin. I suggest we move that out of here and add a PR in that project.
Will start reviewing asap, are you planing to add more changes soon?
@ened
Something initial - the permission check and APIs should be done with permission_handler or any other plugin. I suggest we move that out of here and add a PR in that project.
I created a feature request in permission_handler https://github.com/Baseflow/flutter-permission-handler/issues/1174, although I will not be able to create a PR since that is using purely Objective C not swift, would be nice if someone helps in it. For the time being we can leave the current implementation here in workmanager and when permission_handler releases a version with Background App Refresh permission we will deprecate it here and ask users to switch to permission_handler. Having this permission is necessary since workmanager on iOS will be handicapped if user disables the permission and developers will not know what happened
Will start reviewing asap, are you planing to add more changes soon?
I am done with it for now. Have left one or two TODOs just for code cleanups which I will do once this PRs direction is finalized
Just wanna say thank you @absar for finally building these features out. I'm just started planning features in my app that rely on this, and your timing could not be any better :).
I pulled this in via my pubspec.yaml and am now successfully dispatching one off tasks on iOS. Huge thanks to the author. One note is that to get it to succeed on iOS I had to initialize with isInDebugMode true
  Workmanager().initialize(callbackDispatcher, isInDebugMode: true);
If I did not set that flag when the task was dispatched iOS would throw some error about notifications and the app not being run in debug mode and/or on iOS 9 or lower. Small workaround and with that it all works great.
Tried using real device on iPhone XR using iOS 17.0.3. I can confirm that this update/PR is working well with small piece of example code. Will try to implement in the real project later.
This looks really promising, any plan on when this will be merged? Our app could really use these features
Will look at it asap
Impressive feat! Exactly what was missing for our IOS needs. Will use your branch until it is in the official package. Thanks a lot!
Do you have any schedule to deploy this PR? Please let us know if you can. Many thanks.
@absar  awesome update
already have tested your example in testFlight
and notice that periodic and processing tasks work only when app is in background or foreground state,
but when app is closed(terminated) then tasks don't fired
is it correct behaviour?
Yes it's the correct behavior see [https://developer.apple.com/documentation/backgroundtasks/bgprocessingtask](Apple Doc)
If the app is killed, the BGProcessing is killed too.
Hi, another ping asking when this PR will be merged. Very curious to try it!
Getting an error when trying to build:
Could not build the precompiled application for the device.
Swift Compiler Error (Xcode): Type 'WorkmanagerPlugin' has no member 'registerBGProcessingTask'
On IOS 16.7.5 Xcode 15
I got this working perfectly now! Needed to use a different ref
workmanager:
    git:
      url: https://github.com/absar/flutter_workmanager.git
      ref: 73cc539cd2f1b992b468e6c44f5d0a7919d7ffda
                                    
                                    
                                    
                                
@absar permission_handler now supports the background app refresh check (I sent a PR a while back). We are clear to remove the permission code from your PR and start thinking about the merge. :)
@ened currently am quite occupied, will get back to it, let me know if you have any other reviews for the PR so that I address them in one shot.
For the ones using my branch either use the latest commit hash instead of just the branch name https://github.com/absar/flutter_workmanager/tree/ios-bg-tasks-enh-final or fork it and use it from your own repos, and start migrating the permission Workmanager.checkBackgroundRefreshPermission to permission_handler package mentioned by @ened so that once Workmanager.checkBackgroundRefreshPermission is removed from this PR you are not impacted
Hi, I was looking at refreshing tokens in the background using work manager. On IOS, is it possible to trigger one of task with same ids multiple times? If I have to permit the ids upfront, then I cant register one off task few mins before the token expiry to refresh it. Any suggestions on how to do this?
Also, is it possible to register the one of task (in swift code) with name instead of id?
Hi,
I am trying to run periodic task on ios with below code and settings. Unfortunately, the task isnt getting triggered. Any help would be appreciated.
Swift code:
import UIKit import Flutter import workmanager
@UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { self.window.makeSecure() GeneratedPluginRegistrant.register(with: self) UNUserNotificationCenter.current().delegate = self WorkmanagerPlugin.setPluginRegistrantCallback { registry in // Registry in this case is the FlutterEngine that is created in Workmanager's // performFetchWithCompletionHandler or BGAppRefreshTask. // This will make other plugins available during a background operation. GeneratedPluginRegistrant.register(with: registry) }
WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "com.background_task_manager.token_refresh_task", frequency: NSNumber(value: 20*60))
//UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(20*60));
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler(.alert) // shows banner even if app is in foreground } }
extension UIWindow { func makeSecure() { let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" let isSecureMode = Bundle.main.object(forInfoDictionaryKey: "EnableSecureMode") as! String == "YES" if (isTestFlight || !isSecureMode) { return }
let field = UITextField()
let view = UIView(frame: CGRect(x: 0, y: 0, width: field.frame.self.width, height: field.frame.self.height))
field.isSecureTextEntry = true
self.addSubview(field)
self.layer.superlayer?.addSublayer(field.layer)
field.layer.sublayers?.last!.addSublayer(self.layer)
field.leftView = view
field.leftViewMode = .always
} }
version of the library used
workmanager: git: url: https://github.com/absar/flutter_workmanager.git ref: 73cc539cd2f1b992b468e6c44f5d0a7919d7ffda
Target platform an other details:
platform :ios, '13.0'
Code to trigger period task
      Workmanager().registerPeriodicTask(
  BackgroundTaskKeys.refreshTokenTaskName, // Unique ID for your task
  BackgroundTaskKeys.refreshTokenTaskName,
  initialDelay: Duration(seconds: 10),
  frequency: Duration(seconds: 20*60)
);
Info LIst params
		<key>UIBackgroundModes</key>
    <array>
	    <string>fetch</string>
	    <string>processing</string>
    </array>
    
    
    		<key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
	    <string>com.kdi.background_task_manager.token_refresh_task</string>
    </array>
                                    
                                    
                                    
                                
Merging this, but will require a few iterations before packaging this into a release.
@ened Can you share the ETA for the new release?
Trying to run periodic task on ios results in this error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(unhandledMethod("registerPeriodicTask") error, Unhandled method registerPeriodicTask, null, null)
Works fine on Android though, just an isolated iOS issue
@alfietapping make sure to use the mentioned branch https://github.com/absar/flutter_workmanager/tree/ios-bg-tasks-enh-final instead of using master branch
@absar thanks for this. The error has cleared, but unfortunately nothing actually happens now on iOS, workmanager never triggers any work. I've followed the specific ios setup from the docs, and i do get this line of code fire
BGAppRefreshTask submitted dailyReminder earliestBeginInSeconds:0.0
but it never runs the period task work declared in the main file, perhaps im missing something else?
@alfietapping I have tried it, and it has worked for me.
Did you try opening Xcode, running your app, then in xcode going to 'debug -> simulate background fetch' ?
In my case, by doing that, my periodicTask has been executed after 8 minutes.
I am using the following in my pubspec
workmanager:
   git:
     url: https://github.com/fluttercommunity/flutter_workmanager.git
     ref: b783000
                                    
                                    
                                    
                                
I have the same issue on iOS. registerProcessingTask is not trigger on iOS.
@alfietapping I have tried it, and it has worked for me.
Did you try opening Xcode, running your app, then in xcode going to 'debug -> simulate background fetch' ?
In my case, by doing that, my periodicTask has been executed after 8 minutes.
I am using the following in my pubspec
workmanager: git: url: https://github.com/fluttercommunity/flutter_workmanager.git ref: b783000
Did you try actually running the process on a device and checking it ran work? I haven't tested simulating anything through xcode etc, if it doesn't work on a device then it doesn't function in the real world.
@alfietapping I have tried it, and it has worked for me.
Did you try opening Xcode, running your app, then in xcode going to 'debug -> simulate background fetch' ?
In my case, by doing that, my periodicTask has been executed after 8 minutes.
I am using the following in my pubspec
workmanager: git: url: https://github.com/fluttercommunity/flutter_workmanager.git ref: b783000
i'm in this reference, but not triggered. OneOfTask works normally...
@alfietapping I have tested it on an Iphone 12 pro (physical device) with iOS 17.4.1 and it worked.
Remember to set minimum version iOS 13 in your flutter project.
@alfietapping I have tested it on an Iphone 12 pro (physical device) with iOS 17.4.1 and it worked.
Remember to set minimum version iOS 13 in your flutter project.
I'm in iphone 11, ios 17 with minimum iOS 13...
OneOfTask works normally, but periodic doesn't, I'm not using initialValue, and I set the period to 15 minutes. What else should I try?
I dont understand the steps here https://github.com/fluttercommunity/flutter_workmanager/blob/main/IOS_SETUP.md#testing-bgtaskscheduler
Where is the submit() that i need to find and add a breakpoint.