General:
DevForums tag: Background Tasks
Background Tasks framework documentation
UIApplication background tasks documentation
ProcessInfo expiring activity documentation
watchOS background execution documentation
WWDC 2020 Session 10063 Background execution demystified — This is critical resource. Watch it!
WWDC 2022 Session 10142 Efficiency awaits: Background tasks in SwiftUI
iOS Background Execution Limits DevForums post
UIApplication Background Task Notes DevForums post
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Background Tasks
RSS for tagRequest the system to launch your app in the background to run tasks using Background Tasks.
Posts under Background Tasks tag
135 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Our watch app, Regatta Timer, is a specialised countdown timer for sailing competitions. It is crucial that the beeps & haptics continue when 'wrist down' on alway on displays. We tried to enable this by adding 'background mode' but that only works in the Xcode Apple Watch simulator, not on an actual device with always on display. Any idea how we can get this working also on the Apple Watch device?
In ContentView.swift we currently added this code:
WKInterfaceDevice.current().play(sound)
}
but that doesnt work - regardless of adding , phase == .active`
or not.
STEPS TO REPRODUCE
Install on an ACTUAL DEVICE with always on display
start the countdown timer: beeps & sounds are OK (each minute,...)
do 'wrist down': the countdown timer continues on the dimmed display, but the sounds & haptics stop working until you raise your wrist to wake up the display.
My iOS application can execute a timer in the background on some devices, but it doesn't work on others.
I attached my raw data to this post. The raw data includes the device ID, the iPhone model, and the iOS version.
raw data:
Can someone help me, please!
I am considering to use the BGAppRefreshTask mechanism, and while I think I have read and understood all documentation and hints in this forum about it (especially the limitations), the one thing I do not understand is: how can I debug it? I cannot find a way to trigger the BGAppRefreshTask execution reliably and immediately. I would have expected the Xcode Debug->Simulate Background Fetch menu to do this for me, but it only sends the app into the background.
I am working with the unmodified (except for a few added print()) ColorFeed sample code project from Apple, which schedules a task 15min into the future when it goes to the background. Using a real device, I have not managed to trigger execution of the BGAppRefreshTask more often than once a day so far.
Surely, there must be a way to trigger it much more often solely for debugging and development purposes (I am totally happy with all restrictions for the final app).
So what detail am I missing here?
Hi,
I have requirement in iOS where application needs to run in the background
It can be a simple hello world program running in the background.
could you shed some light on what is the expected behaviour and is it allowed in iOS.
DESCRIPTION OF PROBLEM
Logs and data from our application indicate various errors that strongly suggest that our application is being launched in a state in which the device is likely locked. We are looking for guidance on how to identify, debug, reproduce, and fix these cases.
Our application does not use any of the common mechanisms for background activity, such as Background App Refresh, Navigation, Audio, etc.
Errors we get in our logs such as "authorization denied (code: 23)" when trying to access a file in our app's container on disk (a simple disk cache for data our application uses) strongly suggest that the device is operating in a state, such as being locked, where our application lacks the requisite permissions it would normally have during operation. Furthermore, attempts to access authentication information stored in the keychain also fails. We use kSecAttrAccessibleWhenUnlocked when accessing items we store in the keychain.
We have investigated "Prewarming", as well as our notification extension that helps process incoming push notifications, but cannot find any way to recreate this behavior.
Are there any steps Apple engineers can recommend to triage and debug this?
Some additional questions that would help us:
What are all of the symptoms that we can look for if prewarming escapes the intended execution context?
What are all of the circumstances in which we would be unauthorized to access the app’s documents/file directories even if it works correctly in normal operation?
STEPS TO REPRODUCE
Unfortunately, we are unable to forcibly reproduce this behavior in our application, so we're looking for guidance on how we might simulate this behavior in Xcode / Instruments.
Are there tools that Apple provides that would allow us to simulate certain behaviors like prewarming to verify our application's functionality?
Are there other reasons our application might be launched while the device is locked? Are there other reasons we would receive security errors when accessing the keychain or disk that are unrelated to the device being locked?
I am writing to address a concern regarding the background permission functionality in my app, which is critical for ensuring user safety as they navigate various terrains. This feature also enables users to smoothly record their navigation tracks for review after their activities. Recently, I've noticed that this functionality is not working as seamlessly as before.
Additionally, I observed that the app is not categorized under 'health and fitness'—could reclassifying it improve background activity? Before I delve into a detailed code review, I wanted to check if this issue might be related to sync or settings on the App Store side, such as permission configurations, app updates, or other related factors. Or, is it more likely an issue stemming from the app’s codebase?
I'm working on an application where, once the user starts driving, I need to periodically check their activity every 2.5 minutes (150 seconds) to determine whether they are still driving, walking, or have stopped. If they are still driving, I want to keep rescheduling the task until the user is no longer in a driving state.
Currently, I'm using startMonitoringSignificantLocationChanges to wake the app when the user's location changes, which works as expected. However, the activity detection stops after the first result is received, and I can't continue tracking the user's activity in the background (or after the app is killed from the app switcher).
Here's my approach:
After receiving a significant location change, I start tracking the user’s activity to check if they are driving or have stopped.
I reschedule this task every 2.5 minutes as long as the user remains in a driving state.
I need this process to run even when the app is in the background or terminated by the user.
Question: Is it possible to keep activity detection running periodically after receiving a location change, even when the app is in the background or terminated? What is the recommended way to implement this?
I would appreciate any suggestions or best practices for achieving this functionality.
Hi everyone,
We came an issue that, In some scenarios in our app we cannot fetch any resources from device (Photo and Contact).
One case we catched is putting app in background and spending time in other commonly used apps and coming back to our app cause this issue but there is a small chance that get this issue during using the application.
In cell, we are trying to fetch the image like this
imageFetchTask = Task {
let image = await CompositionRoot.shared.photosManager.image(requestType: .imageCollections, forId: photoAsset.photoId)
self.photoImageView.image(image)
}
and inner layers of this code we get the PHAsset and request image
PHAsset.firstAsset(for: id)
let manager = PHImageManager.default()
manager.requestImage(for: asset, targetSize: request.targetSize, contentMode: .aspectFill, options: request.options) { (image, info) in
continuation.resume(returning: image)
}
We figured out that issue not happening only in Photos also Contacts and
any web request. So any help according to this situation is well appreciated.
Thanks
I have an iOS app, watchOS app, and iOS Widget that shows the most recent data in the database.
The watch app sends data to the iOS app over the WCSession and is received in session(didReceiveMessage, replyHandler). After that data is processed, reloadAllTimelines() is called.
When running in Simulator or on device plugged in to debugger, it works, the widget updates when the app is closed (in background, even if force quit).
But when running TestFlight or App Store build, the data is still processed and saved to Core Data (I open the app and it's there), but the widget doesn't update.
It seems that reloadAllTimelines only works when the app is in foreground (at least in non debug builds). I dont have an iOS 17 device to check but I think this is a recent bug with iOS 18.
Hi everyone,
I’m encountering a recurring issue with my app submission, and I’d appreciate your insights. My app has been rejected due to Guideline 2.5.4 with the following feedback:
Guideline 2.5.4 - Performance - Software Requirements
The app continues to declare support for location in the UIBackgroundModes key in your Info.plist file but we are unable to locate any features besides employee tracking that require persistent location.
Using the location background mode for the sole purpose of tracking employees is not appropriate.
Please note we located the features of the app but the location background tracking of employees is not appropriate with this guideline.
Next Steps
If the app has a feature besides tracking employees that requires persistent location, reply to this message and let us know how to locate this feature. Otherwise, it would be appropriate to revise the app to include additional features for your users that require the persistent use of real-time location updates while the app is in the background
My App’s Use Case:
The app is designed to support events where users can check in and check out. Persistent location tracking is essential for the following:
1. During Events:
• Tracking users’ real-time location ensures they remain within the event boundaries.
• If a user exits the designated area, the system logs the occurrence for compliance and security purposes.
2. Workforce Monitoring:
• For work events, the app records working hours based on their presence within the event area.
• This ensures accurate logging of attendance and work durations.
Steps I’ve Taken:
• Limited Scope of Tracking: Persistent location tracking is active only during event check-in and check-out periods. Outside of these periods, tracking is disabled.
• User Consent: I’ve implemented clear permission requests and a privacy policy to explain how location data is used.
• Info.plist Configuration: I’ve declared the UIBackgroundModes key with location to support background tracking.
Despite these measures, my app continues to be rejected with the feedback above. I believe my app’s features align with the guidelines as the location tracking is directly tied to event functionality and user benefit.
Questions:
1. How can I better explain this use case to Apple’s review team to demonstrate compliance?
2. Are there any additional features or adjustments I should consider to ensure my app meets the guidelines?
3. Has anyone faced a similar issue with persistent location tracking, and how did you resolve it?
Thank you for your guidance and support!
I'm making a Safari extension for learning languages. I need speech synthesis for any language the user chooses to learn.
I initially tried to make this work within JavaScript, but Safari 18 doesn't reliably list voices for all languages on the web SpeechSynthesis API as described here: https://stackoverflow.com/questions/79179072/how-do-you-use-a-japanese-voice-with-speechsynthesis-in-safari-ios-18
As a workaround, I've had to use AVSpeechSynthesizer in SafariWebExtensionHandler (NSExtensionRequestHandling implementation for the extension). This works in the simulator but not on a real device. I've found this note from Apple in a StackOverflow reply:
"Safari extensions are very short-lived, hence not fit for audio playback or speech synthesis. Not being able to validate an app extension in Xcode with a manually-added plist entry for background audio is the designed behavior. The general recommendation is to synthesize speech using JavaScript in conjunction with the Web Speech API."
Unfortunately, the suggestion to use the Web Speech API is unsuitable as I just explained.
Is there a way to set up a background process in the host app that can do speech synthesis? The app extension would need a way to communicate with this process, and start it if it's not running. Is that possible?
I am trying to build a chat app. I am using FCM to deliver messages to my app accompanied by some custom data like the new message_data, deleted message_id and so on; each message will need to run the app in the background to do some background processing and local database syncing.
This continuous background processing is clearly not acceptable as APNs imposes a per-device limit on background push notifications . I am asking how can I push messages and actions payload without being throttled ?
It’s been established that generally speaking background apps cannot record audio while the foreground app is already reading audio data from the microphone, but are there exceptions? For instance, is there an exception for certain Apple apps?
If so, and there’s a special exception that most programmers don’t know about but some Apple’s engineers do and perhaps some hackers do as well, wouldn’t the mechanism that allows that eventually be exploited?
All the nuances of when and whether a background task runs aside, does launching the app cancel the currently scheduled refresh task? As an example, consider the following case:
8AM - user launches app. This launch schedules a background refresh for 12 hours later, at 8PM
12PM (noon) - user launches the app, views some content, then exits the app.
Does the scheduled refresh for 8PM still exist, or does the launch at noon invalidate that task, since the refresh could conceivably be handled during that noon launch?
Hopefully this is articulated clearly enough, but I'm trying to understand the specifics of background refresh behavior, since I don't want to run that refresh every time the app is opened. However, if opening the app invalidates scheduled refreshes, I will need to include logic that will reschedule the refresh accordingly.
I have widgets providing their timeline using the .atEnd reload policy, i.e.:
// AppIntentTimelineProvider:
return Timeline(entries: entries, policy: .atEnd)
// TimelineProvider
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
I can't seem to find any information on what happens after the end of the timeline. So, let's say I've got two days worth of entries, the dev docs for the reload policy say, "A policy that specifies that WidgetKit requests a new timeline after the last date in a timeline passes."
Great! But how does it request the new timeline? Does iOS launch my app in the background and simply re-run the timeline to generate another two days worth of entries? I doubt it.
I figure I need to implement some sort of background task, and the dev docs say how to do it with an Operation, but then I read that this is an old way of doing it? I've found some info online saying to use something like this, so this is what I've implemented:
let kBackgroundWidgetRefreshTask = "my.refresh.task.identifier" // This has been registered in the info.plist correctly
class SchedulingService {
static let shared = SchedulingService()
func registerBackgroundTasks() {
let isRegistered = BGTaskScheduler.shared.register(forTaskWithIdentifier: kBackgroundWidgetRefreshTask, using: nil) { task in
print("Background task is executing: \(task.identifier)") // This does print "true"
self.handleWidgetRefresh(task: task as! BGAppRefreshTask)
}
print("Is the background task registered? \(isRegistered)")
}
func scheduleWidgetRefresh() {
let request = BGAppRefreshTaskRequest(identifier: kBackgroundWidgetRefreshTask)
// Fetch no earlier than 1 hour from now - test, will be two days
request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 60)
do {
try BGTaskScheduler.shared.submit(request)
print("Scheduled widget refresh for one hour from now")
} catch {
print("Could not schedule widget refresh: \(error)")
}
}
private func handleWidgetRefresh(task: BGAppRefreshTask) {
// Schedule a new refresh task
scheduleWidgetRefresh()
// Start refresh of the widget data
let refreshTask = Task {
do {
print("Going to refresh widgets")
try await self.backgroundRefreshWidgets()
task.setTaskCompleted(success: true)
} catch {
print("Could not refresh widgets: \(error)")
task.setTaskCompleted(success: false)
}
}
// Provide the background task with an expiration handler that cancels the operation
task.expirationHandler = {
refreshTask.cancel()
}
}
func backgroundRefreshWidgets() async throws {
print("backgroundRefreshWidgets() called")
definitelyRefreshWidgets()
}
}
As I've commented above, the line print("Background task is executing: \(task.identifier)") does print true so the task has been registered correctly.
I've put the app into the background and left it for hours and nothing is printed to the console. I've implemented a logger that writes to a file in the app container, but that doesn't get anything either.
So, is there something I'm misunderstanding? Should I change the reload policy to .after(date)? But what makes the timeline reload?
As a second but linked issue, my widgets have countdown timers on them and the entire timeline shows that every entry is correct, but the widgets on the Home Screen simply fail to refresh correctly.
For example, with timeline entries for every hour for the next two days from 6pm today (so, 7pm, 8pm...) every entry in the preview in Xcode shows the right countdown timer. However, if you put the widget on the Home Screen, after about five hours the timer shows 25:12:34 (for example).
No entry in the timeline preview ever shows more than 24 hours because the entires are every hour, and the one that shows a timer starting at 23:00:00 should never get to 24:00:00 as the next entry would kick in from 0:00:00, so it should never show more than 23:59:59 on the timer. It's like the 23:00:00 timer is just left to run for hours instead of being replaced by the next entry.
It's as though the widget isn't refreshing correctly and entries aren't loaded? Given this is the Simulator - and my development device - and both are set to Developer Mode so widget refresh budgets aren't an issue, why is this happening? How do you get widgets to refresh properly? The dev docs are not very helpful (neither is the Backyard Birds example Apple keep pushing).
Thanks!
Hi,
I'd like to develop an app which runs speech recognition even after going into background. I know I can accomplish this using audio background mode and the process the audio but I am not sure if this workaround would get accepted into App Store because of the processing limitations while in the background.
How can I accomplish this while still being compliant with Apples privacy policy and other restrictions?
Thanks,
Marek
Hello,
our application works with Core Data to save some datas about its activity.
We have background Tasks implemented and our app execution in background shows this error message in the Logs:
error: Failed to acquire background task assertion for task 'CoreData: Executing write request'.
Anyone could explain what this message means?
Could it be that NSManagedObjectContext changes might not be written?
I have a use case in my app where I need to call an API from the device every 30 minutes to verify the app state. In certain cases, the backend records the time of the last received API call or observes the absence of an API call for business logic, making it crucial that the call is executed at fixed intervals.
I am using React Native to build the app and the react-native-background-fetch package to create the background task. As I understand it, the package uses the Background Fetch API under the hood.
From what I have observed and read from other sources so far, there is no guarantee that the task will run every 30 minutes. Is there any way to make the background task more consistent, or is there a better approach to achieve this objective on iOS?
We have a device which is an appliance and we are developing a control interface app for macOS and iOS/iPadOS.
How can we set up our iOS application to grab information from a local network device while it is in the background in order to show notifications?
Communication between the Apple device and our device is via local networking and the device is designed to be used on networks without internet connections. On networks with internet connections we could forward events from the device, via a server and APNS push notifications, but that isn't valid here.
Events occur on our device and are forwarded to clients, who are subscribed to Server-Sent Events. On macOS this works well and the application can receive updates and show Notification Center notifications fine.
On iOS we are using a BGAppRefreshTaskRequest with time interval set to 1 minute, but it appears that we get scheduled only every few hours. This isn't very useful as notifications just arrive in batches rather than in a timely manner. All normal networking is closed when the app goes into the background, so we cannot keep the SSE request open.
Another idea which we haven't tried yet: Creating a new endpoint on the device which keeps the connection open until a notification arrives, then using background URLSession to poll on that endpoint. Would that work? It seems like a mis-use of the API perhaps?
I have an app, that when enters the background schedules a task to run. The earliest possible time value is set, as is the completion handler when the task eventually runs. It seems to run pretty reliably for the 1st few interations and then (from looking at the streaming Console logs), doesn't seem to reach a high CP score to execute next time around. eg
'......background.task:EDBC23' CurrentScore: 0.648418, ThresholdScore: 0.808034 DecisionToRun:0
looking at the previous entries before this, I can see the breakdown...
{name: Application Policy, policyWeight: 50.000, response: {0, 0.35}}
{name: Device Activity Policy, policyWeight: 5.000, response: {0, 0.50}}
], Decision: CP Score: 0.648418}
and I understand certain elements are outside of our control; however, is there a preferred method to get a background task (which ultimately runs an API call) to trigger consistently? The silent-push method has come up a few times - but of course, if the user disables / doesn't consent to push notifications, that fails
Any suggestions?