Hi,
I'll explain my question through how whatsapp does it.
When the phone is locked then whatsapp routes call through apple's native callkit
When unlocked, pressing accept essentially redirects to whatsapp and then whatsapp handles the call from there.
However, this component of unlock detection is what I'm not able to find any info about.
Essentially,
how i do it is:
let isPhoneLocked = !UIApplication.shared.isProtectedDataAvailable
isProtectedDataAvailable == true → device is unlocked
isProtectedDataAvailable == false → device is locked
The problem is that if the phone has been recently unlocked, then protected data is still available on the phone even after the lock for the next 10-40 seconds. So theres a false positive.
I want there to be a foolproof and robust way to do this. And I'm not entirely sure how
Processes & Concurrency
RSS for tagDiscover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hi everyone,
I’m trying to register fonts system-wide using CTFontManagerRegisterFontURLs with the .persistent scope. The fonts are delivered through Apple-Hosted Background Assets (since On-Demand Resources are deprecated).
Process-level registration works perfectly, but persistent registration triggers a system “Install Fonts” prompt, and tapping Install causes the app to crash immediately.
I’m wondering if anyone has successfully used Apple-Hosted Background Assets to provide persistent, system-wide installable fonts, or if this is a current OS limitation/bug.
What I Expect
Fonts delivered through Apple-Hosted Background Assets should be eligible for system-wide installation
Tap “Install” should install fonts into Settings → Fonts just like app-bundled or ODR fonts
App should not crash
Why This Matters
According to:
WWDC 2019: Font Management and Text Scaling
Developers can build font provider apps that install fonts system-wide, using bundled or On-Demand Resources.
WWDC 2025: Discover Apple-Hosted Background Assets
On-Demand Resources are deprecated, and AHBAs are the modern replacement.
Therefore, persistent font installation via Apple-Hosted Background Assets appears to be the intended path moving forward.
Question
Is this a known limitation or bug in iOS?
Should .persistent font installation work with Apple-Hosted Background Assets?
Do we need additional entitlement, manifest configuration, or packaging rules?
Any guidance or confirmation from Apple engineers would be greatly appreciated.
Additional Info
I submitted a Feedback including a minimal reproducible sample project:
FB21109320
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Core Text
Background Assets
Typography
Concurrency
As far as I understand, the main thread has a run loop.
When an iOS app launches, the process must keep the run loop running to stay alive.
Does that mean the main thread is the very first thread created when the process starts?
Currently I am trying to find a work around to fetch data from server and update user defaults when app is forced quit. Can anyone suggest for this ?
The same code built in a regular Mac app (with UI) does get paired.
The characteristic properties are [.read, .write, .notify, .notifyEncryptionRequired]
The characteristic permissions are [.readEncryptionRequired, .writeEncryptionRequired]
My service is primary.
In the iOS app (central) I try to read the characteristic, but an error is reported: Error code: 5, Description: Authentication is insufficient.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Service Management
Core Bluetooth
I’m looking for an authoritative answer on how BGAppRefreshTask behaves after a user force-quits an app (swipes it away in the App Switcher).
My app relies on early-morning background refresh to prepare and schedule notifications based on user-defined thresholds and weather forecasts.
Behavior across devices seems inconsistent, however: sometimes a scheduled background refresh still runs, and other times it appears completely blocked.
Apple’s documentation doesn’t clearly state what should happen, and developer discussions conflict.
Could someone from Apple please clarify:
Will a previously scheduled BGAppRefreshTask run after the user force-quits the app?
If not, is there a recommended alternative for time-sensitive updates that must schedule user alerts?
What is the expected system behavior regarding the predictability of background refresh after a force-quit?
A definitive answer would help ensure the app aligns with intended system behavior.
Thanks!
Hi there,
First thanks for all the work on BGContinuedProcessingTask! It looks really promising.
I have a question / issue around the behavior when a BGContinuedProcessingTask expires. Here is my setup.
I have an app who's responsible for uploading large files in the field (AKA wifi is not expected)
For a given file, it can likely fail due to network conditions
I'm using Multipart upload though so I can retry a file to pick up where it left off.
I use one taskIdentifier per file, and when the file fails, I can retry the task and have it continue where it left off (I am reusing the taskIdentifier here for retries, let me know if I shouldn't be doing that)
Here is the behavior I am seeing
I start an upload, it seems to be uploading normally
I turn on airplane mode to simulate expiration of the task
the task fails as expected after ~30 seconds, and I see the failure in my home screen.
I have callbacks in the task to put my app in the proper state on expiration / failure
I turn back on airplane mode and I retry the task, the way I do this is I do NOT re-register, I simply re-submit the task with the same TaskIdentifier.
What I would have expected is that the failure task is REPLACED with the new task and new progress. Instead what I see is TWO ContinuedBackgroundProcessingTasks, one in the failure state and one in progress.
My question is
How can I make retries reuse the same task notification item?
OR if that's not possible, how do I programmatically clear the task failure? I've tried cancelTask but that doesn't seem to clear it.
I've experimentally seen that the notifications(named:) API of NotificationCenter appears to buffer observed notifications internally. In local testing it appears to be limited to 8 messages. I've been unable to find any documentation of this fact, and the behavior seems like it could lead to software bugs if code is not expecting notifications to potentially be dropped. Is this behavior expected and documented somewhere?
Here is a sample program demonstrating the behavioral difference between the Combine and AsyncSequence-based notification observations:
@Test
nonisolated func testNotificationRace() async throws {
let testName = Notification.Name("TestNotification")
let notificationCount = 100
var observedAsyncIDs = [Int]()
var observedCombineIDs = [Int]()
let subscribe = Task { @MainActor in
print("setting up observer...")
let token = NotificationCenter.default.publisher(for: testName)
.sink { value in
let id = value.userInfo?["id"] as! Int
observedCombineIDs.append(id)
print("🚜 observed note with id: \(id)")
}
defer { extendLifetime(token) }
for await note in NotificationCenter.default.notifications(named: testName) {
let id: Int = note.userInfo?["id"] as! Int
print("🚰 observed note with id: \(id)")
observedAsyncIDs.append(id)
if id == notificationCount { break }
}
}
let post = Task { @MainActor in
for i in 1...notificationCount {
NotificationCenter.default.post(
name: testName,
object: nil,
userInfo: ["id": i]
)
}
}
_ = await (post.value, subscribe.value)
#expect(observedAsyncIDs.count == notificationCount) // 🛑 Expectation failed: (observedAsyncIDs.count → 8) == (notificationCount → 100)
#expect(observedCombineIDs == Array(1...notificationCount))
print("done")
}
Hi everyone, could you help us?
We implemented a Flutter library that basically makes a call every x minutes if the app is in the background, but when I generate the version via TestFlight for testing, it doesn't work.
Can you help us understand why?
Below is a more detailed technical description.
Apple Developer Technical Support Request
Subject: BGTaskScheduler / Background Tasks Not Executing in TestFlight - Flutter App with workmanager Plugin
Issue Summary
Background tasks scheduled using BGTaskScheduler are not executing when the app is distributed via TestFlight. The same implementation works correctly when running the app locally via USB/Xcode debugging.
We are developing a Flutter application that needs to perform periodic API calls when the app is in the background. We have followed all documentation and implemented the required configurations, but background tasks are not being executed in the TestFlight build.
App Information
Field
Value
App Version
3.1.15 (Build 311)
iOS Minimum Deployment Target
iOS 15.0
Framework
Flutter
Flutter SDK Version
^3.7.2
Technical Environment
Flutter Dependencies (Background Task Related)
Package
Version
Purpose
workmanager
^0.9.0+3
Main background task scheduler (uses BGTaskScheduler on iOS 13+)
flutter_background_service
^5.0.5
Background service management
flutter_background_service_android
^6.2.4
Android-specific background service
flutter_local_notifications
^19.4.2
Local notifications for background alerts
timezone
^0.10.0
Timezone support for scheduling
Other Relevant Flutter Dependencies
Package
Version
firebase_core
4.0.0
firebase_messaging
(via native Podfile)
sfmc (Salesforce Marketing Cloud)
^9.0.0
geolocator
^14.0.0
permission_handler
^12.0.0+1
Info.plist Configuration
We have added the following configurations to Info.plist:
UIBackgroundModes
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>remote-notification</string>
<string>processing</string>
</array>
### BGTaskSchedulerPermittedIdentifiers
```xml
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>br.com.unidas.apprac.ios.workmanager.carrinho_api_task</string>
<string>br.com.unidas.apprac.ios.workmanager</string>
<string>be.tramckrijter.workmanager.BackgroundTask</string>
</array>
**Note:** We included multiple identifier formats as recommended by the `workmanager` Flutter plugin documentation:
1. `{bundleId}.ios.workmanager.{taskName}` - Custom task identifier
2. `{bundleId}.ios.workmanager` - Default workmanager identifier
3. `be.tramckrijter.workmanager.BackgroundTask` - Plugin's default identifier (as per plugin documentation)
## AppDelegate.swift Configuration
We have configured the `AppDelegate.swift` with the following background processing setup:
```swift
// In application(_:didFinishLaunchingWithOptions:)
// Configuration to enable background processing via WorkManager
// The "processing" mode in UIBackgroundModes allows WorkManager to use BGTaskScheduler (iOS 13+)
// This is required to execute scheduled tasks in background (e.g., API calls)
// Note: User still needs to have Background App Refresh enabled in iOS settings
if UIApplication.shared.backgroundRefreshStatus == .available {
// Allows iOS system to schedule background tasks with minimum interval
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
}
## WorkManager Implementation (Dart/Flutter)
### Initialization
```dart
/// Initializes WorkManager
static Future<void> initialize() async {
await Workmanager().initialize(callbackDispatcher, isInDebugMode: false);
print('WorkManagerService: WorkManager initialized');
}
### Task Registration
/// Schedules API execution after a specific delay
## Observed Behavior
### Works (Debug/USB Connection)
- When running the app via Xcode/USB debugging
- Background tasks are scheduled and executed as expected
- API calls are made successfully when the app is backgrounded
### Does NOT Work (TestFlight)
- When the app is distributed via TestFlight
- Background tasks appear to be scheduled (no errors in code)
- Tasks are **never executed** when the app is in background
- We have tested with:
- Background App Refresh enabled in iOS Settings
- App used frequently
- Device connected to WiFi and charging
- Waited for extended periods (hours)
## Possible heart points
1. **Are there any additional configurations required for `BGTaskScheduler` to work in TestFlight/Production builds that are not required for debug builds?**
2. **Is the identifier format correct?** We are using:
`br.com.unidas.apprac.ios.workmanager.carrinho_api_task`
- Should it match exactly with the task name registered in code?
3. **Are there any known issues with Flutter's `workmanager` plugin and iOS BGTaskScheduler in production environments?**
4. **Is there any way to verify through logs or system diagnostics if the background tasks are being rejected by the system?**
5. **Could there be any conflict between our other background modes (`location`, `remote-notification`) and `processing`?**
6. **Does the Salesforce Marketing Cloud SDK (SFMC) interfere with BGTaskScheduler operations?**
## Additional Context
- We have verified that `Background App Refresh` is enabled for our app in iOS Settings
- The app has proper entitlements for push notifications and location services
- Firebase, SFMC (Salesforce Marketing Cloud), and other SDKs are properly configured
- The issue is **only** present in TestFlight builds, not in debug/USB-connected builds
## References
- [Apple Documentation - BGTaskScheduler](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler)
- [Apple Documentation - Choosing Background Strategies](https://developer.apple.com/documentation/backgroundtasks/choosing_background_strategies_for_your_app)
Thank you
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Regarding the Background Assets capability on iOS:
In the install scenario, resources defined as the "install" type are incorporated into the App Store download progress. Do resources of the "update" type in the update scenario also get incorporated into the App Store download progress in the same way?
If an exception occurs during the download of install-type resources and the download cannot proceed further, will the system no longer actively block users from launching the app and instead enable the launch button?
Currently, if a user has enabled automatic updates on their device, after the app is updated and released on the App Store, will the Background Assets download start immediately once the automatic update completes? Or does Background Assets have its own built-in scheduling logic that prevents it from running concurrently with the automatic update?
We're developing an Electron app for MacOS App Store. When updating our app through TestFlight, TestFlight prompts "Close This App to Update", and when I click "Continue" our app would be "Terminated" for update.
Now this is where things go wrong. On MacOS 15 our app seems to be gracefully terminating (We attached it with lldb and it shows that our app returns with 0 when we click "Continue") which is fine.
However for MacOS 26 though, it seems that TestFlight just directly SIGKILLs our app (indicated by lldb), which means that all of our app's child processes are left orphaned. Even worse, our app is singleton, which means that when the app relaunches it fails, because the leftover child processes from the previously SIGKILLed session is still alive, and even if we want to kill those orphaned child processes we can't because our app is sandboxed thus cannot kill processes outside of the current sandbox.
We captured output from log stream (app name redacted):
12-02 22:08:16.477036-0800 0x5452 Default 0x5a4a7 677 7 installcoordinationd: [com.apple.installcoordination:daemon] -[IXSCoordinatorProgress setTotalUnitsCompleted:]: Progress for coordinator: [com.our.app/Invalid/[user-defined//Applications/OurApp.app]], Phase: IXCoordinatorProgressPhaseLoading, Percentage: 99.454 123: Attempt to set units completed on finished progress: 214095161 2025-12-02 22:08:16.483056-0800 0x53ba Default 0x5a5c9 167 0 runningboardd: (RunningBoard) [com.apple.runningboard:connection] Received termination request from [osservice<com.apple.installcoordinationd(274)>:677] on <RBSProcessPredicate <RBSProcessBundleIdentifierPredicate "com.our.app">> with context <RBSTerminateContext| explanation:installcoordinationd app:[com.our.app/Invalid/[user-defined//Applications/OurApp.app]] uuid:A3BC0629-124E-4165-ABB7-1324380FC354 isPlaceholder:N re portType:None maxTerminationResistance:Absolute attrs:[ 2025-12-02 22:08:16.488651-0800 0x53ba Default 0x5a5c9 167 7 runningboardd: (RunningBoard) [com.apple.runningboard:ttl] Acquiring assertion targeting system from originator [osservice<com.apple.installcoordinationd(274)>:677] with description <RBSAssertionDescriptor| "installcoordinationd app:[com.our.app/Invalid/[user-defined//Applications/OurApp.app]] uuid:A3BC0629-124E-4165-ABB7-1324380FC354 isPlaceholder:N" ID:167-677-1463 target:system attributes:[ 2025-12-02 22:08:16.489353-0800 0x53ba Default 0x5a5c9 167 0 runningboardd: (RunningBoard) [com.apple.runningboard:process] [app<application.com.our.app.485547.485561(501)>:2470] Terminating with context: <RBSTerminateContext| explanation:installcoordinationd app:[com.our.app/Invalid/[user-defined//Applications/OurApp.app]] uuid:A3BC0629-124E-4165-ABB7-1324380FC354 isPlaceholder:N reportType:None maxTerminationResistance:Absolute attrs:[ 2025-12-02 22:10:23.920869-0800 0x5a5a Default 0x5a4c6 674 14 appstoreagent: [com.apple.appstored:Library] [A95D57D7] Completed with 1 result: <ASDApp: 0xc932a8780>: {bundleID = com.our.app; completedUnitCount = 600; path = /Applications/OurApp.app; installed = 0} 2025-12-02 22:10:32.027304-0800 0x5ae5 Default 0x5a4c7 674 14 appstoreagent: [com.apple.appstored:Library] [BEB5F2FD] Completed with 1 result: <ASDApp: 0xc932a8780>: {bundleID = com.our.app; completedUnitCount = 600; path = /Applications/OurApp.app; installed = 0} 2025-12-02 22:10:36.542321-0800 0x5b81 Default 0x5a4c8 674 14 appstoreagent: [com.apple.appstored:Library] [185B9DD6] Completed with 1 result: <ASDApp: 0xc932a8780>: {bundleID = com.our.app; completedUnitCount = 600; path = /Applications/OurApp.app; installed = 0}
The line "Terminating with context" seems suspicious. This line is not seen on MacOS 15, only MacOS 26. Is this documented behavior? If so, how can we handle this?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
App Store
Mac App Store
TestFlight
Hi All,
In continuation of this thread https://developer.apple.com/forums/thread/804439
I want to perform data upload after getting it from the BLE device. As state restoration wake should not deal with data upload i though of using a processing task to perform the data upload.
So the flow will be something like:
Connect to device -> listen to notification -> go to background -> wake from notification -> handle data download from ble device -> register processing task for data upload -> hopefully get the data uploaded
From reading about processing task i understand that the task execution is completely handled by the OS and depends on user behaviour and app usage. I even saw that if the user is not using the app for a while, the OS might not even perfoirm the task. So my quesiton is: does state restoration wakeup and perfroming data dowloads in the backgound considered app usage that will increase the likeluhood the task will get execution time?
Can we rely on this for a scenario that the user opens the app for the first time, register, onboard for ble, connect to devie and then put it in the background for days or weeks and only relying on state restoration and processing tasks to do their thing?
Sorry for the long read and appreciate your support!
Shimon
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Background Tasks
Core Bluetooth
I posted here https://developer.apple.com/forums/thread/805554?page=1#867766022 but posting again for visibility (and let me know how I can file a bug)
There was a response in that thread that said you could use the childProgress system to help updating progresses to keep the backgroundTask alive.
What I've found is that using childProgresses results in more terminations than if you just updated the progress directly.
Here is my setups to test this
A BGContinuedProcessingTask that uses URLSessions to upload, and registers the task.progress with the Urlsession Progress
Same, but the task.progress gets updated via a UrlSession Callback
The second is MUCH more stable out in the field in cellular settings, the first fails extremely frequently.
My suspicion is that in the documentation here https://developer.apple.com/documentation/foundation/progress#Reporting-Progress-for-Multiple-Operations
it explicitly states
The completedUnitCount property for a containing progress object only updates when the suboperation is 100% complete. The fractionCompleted property for a containing progress object updates continuously as work progresses for all suboperations.
I wonder if BGContinuedProcessingTask is only looking at completedUnitCount for progress, and not fractionCompleted?
In either case, I would love to use the childProgresses because there are bugs with retries by updating the progress manually, so would love some help resolving this, Thanks!
I've tuned my task to be decently resilient, but I found a few issues that caused it to expire regularly.
excessive CPU usage -> I'm actually running it behind ReactNative, and I found an issue where I was still updating ReactNative and thus it was keeping it alive the entire time the task was running. Removing this update helped improve stability
not updating progress frequently enough ( see https://developer.apple.com/forums/thread/809182?page=1#868247022)
My feature request is, would it be possible to get a reason the task was expired in task.expirationHandler? That would be helpful for both the user and for debugging why the task was expired. Thanks!
Hi there,
I'm trying to work on an architecture where one app exposes an API (Extension Host) that other apps can plugin to. I've been reading all I can from the docs and whatever I can find online. It seemed like iOS26 added the ability to do such a thing (at least in early builds).
Is that the case?
Has the functionality been walked back such that extensions can only be loaded in iOS from within the single app bundle?
My use case is the following:
I'm working on an agent app that desires to have 3rd party developers add functionality (think how MCP servers add functionality to LLMs). The 3rd party plugins would be provided in their own app bundles vetted by the AppStore review team, of course, and would only provide hooks, basically, the main app can use to execute functions or get state.
This is the best thread I found on the topic, and the subtext is that it needs to be in the same bundle. https://developer.apple.com/forums/thread/803896?answerId=865314022#865314022
Let's say for the moment that this isn't possible using ExtensionKit. What's the best way to achieve this? Our current best alternative idea is a hidded WebKit window that runs JS/WASM but that's so hackish.
Please let me know, thanks!
Hello everybody!
I'm currently working on a Bluetooth Low Energy Sync that is using BGTaskScheduler & successfully running periodically in the Background on iOS 26. I did watch this years WWDC Session 227 (Finish tasks in the background) & follow the recommendations as suggested.
Currently, the App is only using 37 Mb (iPhone 12 mini) & no Location or other services are running in Background.
However, when opening Safari & scrolling through some webpages, the App is killed because of "Terminated due to memory issue". I profiled the App & followed advice when it comes to reducing the memory footprint of the App. Are there any additional steps I can take to prevent the App being killed? Are there any recommendations for periodically scheduled Tasks when it comes to the Interval? Do more frequent Tasks (30min compared to one or two hours) have any impact? I tried many different schedules but none seem to make a difference.
From my observation, the App is first suspended & eventually killed because of the Memory Pressure. Any hints, suggestions or recommendations are highly appreciated!
Thanks a lot for the support!
We are seeing a strange lifecycle issue on multiple MDM-managed iPads where
application(_:didFinishLaunchingWithOptions:) is not called after the device is idle overnight.
Even if we terminate the app manually via the app switcher, the next morning the system does not perform a cold launch. Instead, the app resumes directly in:
applicationDidBecomeActive(_:)
This causes all initialization logic that depends on didFinishLaunching to be completely skipped.
This behavior is consistent across four different supervised MDM devices.
Environment
Devices: iPads enrolled in MDM (supervised)
iOS version: 18.3
Xcode: 16.4
macOS: Sequoia 15.7.2
App type: Standard UIKit iOS app
App: Salux Audiometer (App Store app)
Expected Behavior
If the app was terminated manually using the app switcher, the next launch should:
Start a new process
Trigger application(_:didFinishLaunchingWithOptions:)
Follow the normal cold-start lifecycle
Actual Behavior
After leaving the iPad idle overnight (8–12 hours):
The next launch skips didFinishLaunching
The app resumes directly in applicationDidBecomeActive
No new process is started
App behaves as if it had been suspended, even though it was manually terminated
Logs (Relevant Extracts)
Day 1 — Normal cold launch
[12:06:44.152 PM] PROCESS_STARTED
[12:06:44.214 PM] DID_FINISH_LAUNCHING_START launchOptions=[]
[12:06:44.448 PM] DID_FINISH_LAUNCHING_END
We then used the app and terminated it via app switcher.
Day 2 — Unexpected resume without cold start
[12:57:49.328 PM] APP_DID_BECOME_ACTIVE
No PROCESS_STARTED
No didFinishLaunching
No cold-start logs
This means the OS resumed the app from a previous state that should not exist.
Reproducible Steps
Use an MDM-enrolled iPad.
Launch the app normally.
Terminate it manually via the multitasking app switcher.
Leave the device idle overnight (8–12 hours).
Launch the app the next morning.
Observe that:
didFinishLaunching does not fire
applicationDidBecomeActive fires directly
Questions for Apple Engineers / Community
Is this expected behavior on MDM-supervised devices in iOS 18?
Are there any known OS-level changes where terminated apps may be revived from disk/memory?
Could MDM restrictions or background restoration policies override app termination?
How can we ensure that our app always performs a clean initialization when launched after a long idle period?
Additional Information
We have full logs from four separate MDM iPads showing identical behavior.
Happy to share a minimal reproducible sample if required.
Regarding App Update Synchronization During Workout Mode:
My watchOS app has workout mode enabled. When I update the app from the App Store on my iPhone while a workout session is active on my Apple Watch, the update does not sync to the watch. Why does this happen, and when can I expect the watch app to be updated?
Regarding Automatic App Launch After a Prolonged Shutdown:
I would like my watchOS app to launch automatically on my Apple Watch after it has been powered off for an extended period and then turned back on. Is this functionality possible to implement? If not, please provide a definitive answer regarding this capability.