I regularly see questions, both here on the Apple Developer Forums and in my Day Job™ at DTS, that are caused by a fundamental misunderstanding of how background execution works on iOS. These come in many different variants, for example:
How do I keep my app running continuously in the background?
If I schedule a timer, how do I get it to fire when the screen is locked?
How do I run code in the background every 15 minutes?
How do I set up a network server that runs in the background?
How can my app provide an IPC service to another one of my apps while it’s in the background?
How can I resume my app in the background if it’s been ‘force quit’ by the user?
The short answer to all of these is You can’t. iOS puts strict limits on background execution. Its default behaviour is to suspend your app shortly after the user has moved it to the background; this suspension prevents the process from running any code.
There’s no general-purpose mechanism for:
Running code continuously in the background
Running code at some specific time in the background
Running code periodically at a guaranteed interval
Resuming in the background in response to a network or IPC request [1]
However, iOS does provide a wide range of special-purpose mechanisms for accomplishing specific user goals. For example:
If you’re building a music player, use the audio background mode to continue playing after the user has moved your app to the background.
If you’re building a timer app, check out the AlarmKit framework. On older systems, use a local notification to notify the user when your timer has expired.
If you’re building a video player app, use AVFoundation’s download support.
Keep in mind that the above is just a short list of examples. There are many other special-purpose background execution mechanisms, so you should search the documentation for something appropriate to your needs.
IMPORTANT Each of these mechanisms fulfils a specific purpose. Do not attempt to use them for some other purpose. Before using a background API, read clause 2.5.4 of the App Review Guidelines.
Additionally, iOS provides some general-purpose mechanisms for background execution:
To resume your app in the background in response to an event on your server, use a background notification (aka a ‘silent’ push). For more information, see Pushing background updates to your App.
To request a small amount of background execution time to refresh your UI, use the BGAppRefreshTaskRequest class.
To request extended background execution time, typically delivered overnight when the user is asleep, use the BGProcessingTaskRequest class.
To continue user-visible work after the user has left your app, use the BGContinuedProcessingTask class.
To prevent your app from being suspended for a short period of time so that you can complete some user task, use a UIApplication background task. For more information on this, see UIApplication Background Task Notes.
To download or upload a large HTTP resource, use an URLSession background session.
All of these mechanisms prevent you from abusing them to run arbitrary code in the background. As an example, consider the URLSession resume rate limiter.
For more information about these limitations, and background execution in general, I strongly recommend that you watch WWDC 2020 Session 10063 Background execution demystified [2]. It’s an excellent resource.
Specifically, this talk addresses a common misconception about the app refresh mechanism (BGAppRefreshTaskRequest and the older background fetch API). Folks assume that app refresh will provide regular background execution time. That’s not the case. The system applies a range of heuristics to decide which apps get app refresh time and when. This is a complex issue, one that I’m not going to try to summarise here, but the take-home message is that, if you expect that the app refresh mechanism will grant you background execution time, say, every 15 minutes, you’ll be disappointed. In fact, there are common scenarios where it won’t grant you any background execution time at all! Watch the talk for the details.
[1] iOS 26 introduced support for general-purpose IPC, in the form of enhanced security helper extensions. However, these can only be invoked by the container app, and that means there’s no background execution benefit.
[2] Sadly the video is currently not available from Apple. I’ve left the link in place just in case it comes back.
When the user ‘force quits’ an app by swiping up in the multitasking UI, iOS interprets that to mean that the user doesn’t want the app running at all. So:
If the app is running, iOS terminates it.
iOS also sets a flag that prevents the app from being launched in the background. That flag gets cleared when the user next launches the app manually.
This gesture is a clear statement of user intent; there’s no documented way for your app to override the user’s choice.
Note In some circumstances iOS will not honour this flag. The exact cases where this happens are not documented and have changed over time.
Finally, if you have questions about background execution that aren’t covered by the resources listed here, please open a new thread on the forums with the details. Put it in a reasonable subtopic and tag it appropriately for the technology you’re using; if nothing specific springs to mind, use Background Tasks. Also, make sure to include details about the specific problem you’re trying to solve because, when it comes to background execution, the devil really is in the details.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Change history:
2026-01-09 Added a reference to AlarmKit. Added a reference to BGContinuedProcessingTask. Add a footnote about IPC and another one about WWDC 2020 Session 10063. Made other minor editorial changes.
2024-03-21 Added a discussion of ‘force quit’.
2023-05-11 Added a paragraph that explains a common misconception about the app refresh mechanism. Made other minor editorial changes.
2021-08-12 Added more entries to the common questions list, this time related to networking and IPC. Made minor editorial changes.
2021-07-26 Extended the statement about what’s not possible to include “running code periodically at a guaranteed interval”.
2021-07-22 First posted.