Background fetch in iOS 13

I've learned that ...

performFetchWithCompletionHandler

...is Deprecated in iOS 13.


I'm looking for simple example code for retro-fitting my code for background URL sessions to be compatible with iOS 13.


My app uses Background Fetch to grab repeating updates of web data whenever the app is in the background. It works pretty well. The main issue is that the time allocation by iOS is unpredictable. Anyway, now I want to ensure my app is ready for iOS 13. I've already addressed Dark Mode.


The example code provided at WWDC 19 for performing background tasks...

developer.apple.com/documentation/backgroundtasks/refreshing_and_maintaining_your_app_using_background_tasks

...is useful but I'm finding it overly complex (Mock servers, Persistent Containers, etc.). Adapting this example to my app is daunting.


I've found another writeup up. I haven't worked through it yet but it looks promising.

dzone.com/articles/how-to-update-app-content-with-background-tasks-us


If anyone here knows of other good examples of background URL fetches, I'd appreciate some help.

Replies

I'm confused. In the WWDC 2019 video on "Advances in App Background Execution", at about 19:40, the speaker says that performFetchWithCompletionHandler will continue to be supported on iOS devices but not on Mac.


However the Apple documentation for performFetchWithCompletionHandler says it's been deprecated for iOS 13 and above.


Which is it? I need to know if I need to panic and rewrite things for iOS 13 compatibility, or if I have some more time to sort this out.


My confusion runs deeper than that. The background fetching I'm doing invloves setting up a background URL session with a couple of download tasks, catching any errors that arise, and processing the data that come back. I'm having trouble understanding how much of that code, if any, needs to be updated for the new BGAppRefreshTask framework. Does the new framework only affect the scheduling and timing of the fetches, but the setup and handling of the backgroundURL sessions will be unchanged?

>>I'm confused. In the WWDC 2019 video on "Advances in App Background Execution", at about 19:40, the speaker says that performFetchWithCompletionHandler will continue to be supported on iOS devices but not on Mac.


I take it that that means it will work on iOS 13 even though it is deprecated. Usually this is done for folks who still need to deploy to iOS 12. But if you are targeting iOS 13 only, they really would rather you use the new API.


Retrofitting shouldn't be too hard. Doesn't look like much of a change (in the background app refresh department) except they explicitly have an expirationHandler the system will call for you. In the old way they told us "you have 30 seconds to do what needs to be done". So to cancel the "old way" you'd have to use dispatch_after and cancel the running operation. But maybe the system could afford to give you more than 30 seconds, so cancelling seems kind of silly that way. Now that the system tells us time is up, at least you don't have to call your cancel code on a timer.

>> I take it that that means it will work on iOS 13 even though it is deprecated.


Confirmed. Today I bit the bullet and let my iPhone 7+ update itself to iOS 13.1.2 and my background URL session stuff appears to all be working without issue. That's using all old code. I'll start experimenting with the new code soon, since it looks like the URL session stuff is unchanged. It's just the details of starting and ending the background fetch that apparently have changed.


>> Now that the system tells us time is up, at least you don't have to call your cancel code on a timer.


Ah, OK, that's interesting. I currently have a timer set to 20 seconds, so looking forward to updating that.


About the only problem I'm seeing is one being seen by many, a rude debugger message:

Can't end BackgroundTask: no background task exists with identifier 10 (0xa), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug

This doesn't cause any real problems for the app - it keeps running fine.


{UPDATE} Nuts, you cannot run the old code and the new code in the same project. When you register a BGTask indentifier into your plist, as required to use the new framework, that kills any performFetchWithCompletionHandler. So it's all or nothing.

>> {UPDATE} Nuts, you cannot run the old code and the new code in the same project. When you register a BGTask indentifier into your plist, as required to use the new framework, that kills any performFetchWithCompletionHandler. So it's all or nothing.


I've discovered that this is not true despite being in the documentation. The same project can run fine in iOS 12 and iOS 13 as long as you catch the iOS13-specific code and handle it differently. You have to have your code ignore the deprecated performFetchWithCompletionHandler if you're using the new BGAppRefresh approach. But they can coexist.