I have tried to implement background fetch, to hopefully can wake the app from time to time.
I have done these:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
application.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
return true
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
debugPrint("performFetchWithCompletionHandler")
getData()
completionHandler(UIBackgroundFetchResult.newData)
}
func getData(){
debugPrint("getData")
}
I have also enable background fetch capabilities already. That's all i have done. And then i run the app. the function never called even after an hour (the phone slept).
What other things i have to do to make the function get called?
You have done many of the necessary steps:
Turned on "background fetch" the the "Capabilities" tab of your project;
Implemented
application(_:performFetchWithCompletionHandler:)
;Called
setMinimumBackgroundFetchInterval(_:)
inapplication(_:didFinishLaunchingWithOptions:)
.That having been said, a couple of observations:
I'd check the permissions for the app in "Settings" » "General" » "Background App Refresh". This ensures that not only did you successfully request background fetch in your plist, but that it's enabled in general, as well as for your app in particular.
Make sure you're not killing the app (i.e. by double tapping on the home button and swiping up on your app for force the app to terminate). If the app is killed, it will prevent background fetch from working correctly.
You're using
debugPrint
, but that only works when running it from Xcode. But you should be doing this on a physical device, not running it from Xcode. You need to employ a logging system that shows you activity even when not running the app through Xcode.I use
os_log
and watch it from the Console (see WWDC 2016 Unified Logging and Activity Tracing) or use post a notification via the UserNotifications framework (see WWDC 2016 Introduction to Notifications) so I'm notified when app does something notable in the background. Or I've created my own external logging systems (e.g. writing to some text file or plist). But you need some way of observing the activity outside ofprint
/debugPrint
because you want to test this while not running it independently of Xcode. Any background-related behaviors change while running an app connected to the debugger.As PGDev said, you don't have control over when the background fetch takes place. It considers many poorly documented factors (wifi connectivity, connected to power, user's app usage frequency, when other apps might be spinning up, etc.).
That having been said, when I enabled background fetch, ran the app from the device (not Xcode), and had it connected to wifi and power, the first background fetch called appeared on my iPhone 7+ within 10 minutes of suspending the app.
Your code isn't currently doing any fetch request. That raises two concerns:
Make sure that the test app actually issues
URLSession
request at some point its normal course of action when you run it (i.e. when you run the app normally, not via background fetch). If you have a test app that doesn't issue any requests, it doesn't appear to enable the background fetch feature. (Or at the very least, it severely affects the frequency of the background fetch requests.)Reportedly, the OS will stop issuing subsequent background fetch calls to your app if prior background fetch calls didn't actually result in a network request being issued. (This may be a permutation of the prior point; it's not entirely clear.) I suspect Apple is trying to prevent developers using background fetch mechanism for tasks that aren't really fetching anything.
Note, your app doesn't have much time to perform the request, so if you are issuing a request, you might want to inquire solely whether there is data available, but not try to download all the data itself. You can then initiate a background session to start the time consuming downloads. Obviously, if the amount of data being retrieved is negligible, then this is unlikely to be a concern, but make sure you finish your request call the background completion reasonably quickly (30 seconds, IIRC). If you don't call it within that timeframe, it will affect if/when subsequent background fetch requests are attempted.
If the app is not processing background requests, I might suggest removing the app from the device and reinstalling. I've had situation where, when testing background fetch where the requests stopped working (possibly as a result of a failed background fetch request when testing a previous iteration of the app). I find that removing and re-installing it is a good way to reset the background fetch process.
For sake of illustration, here is an example that performs background fetches successfully. I've also added UserNotifications framework and
os_log
calls to provide a way of monitoring the progress when not connected to Xcode (i.e. whereprint
anddebugPrint
no longer are useful):And the view controller merely requests permission for user notifications and issues some random request:
Background Fetch is automatically initiated by the system at appropriate intervals.
For testing whether the code you wrote works properly or not, you can refer to Raywenderlich's tutorial on Background Fetch.
Tutorial: https://www.raywenderlich.com/143128/background-modes-tutorial-getting-started (Search for: Testing Background Fetch)