Delve into the world of built-in app and system services available to developers. Discuss leveraging these services to enhance your app's functionality and user experience.

Posts under General subtopic

Post

Replies

Boosts

Views

Activity

ImageAnalyzer running VNRecognizeTextRequest in the background?
Using VisionKit, there's two main ways to get text from images. ImageAnalyzer VNRecognizeRequest Based on some OCR tests, I'm seeing that the outputs from these two methods are different. Initially, I thought ImageAnalyzer was running VNRequestTextRecognitionLevel.fast because it's for Live Text, but the outputs from ImageAnalyzer are sometimes better than VNRequestTextRecognitionLevel.accurate. Is ImageAnalyzer running VNRequestTextRecognition in the background? Or if it isn't, what pipeline is it using to detect text?
1
2
1.1k
4w
Security architecture and asset protection for Apple-hosted Background Assets
We're evaluating Apple-hosted Background Assets for an app distributed on App Store and would like to understand the security model behind it before adopting it. So far the public documentation only mentions the HTTPS requirement for asset transport. We'd appreciate any additional documentation or guidance covering: How asset downloads are authenticated (e.g., is access tied to the app's entitlement/provisioning, or is there a separate token/credential mechanism?) How access to specific assets is controlled/scoped Where Apple-hosted assets are physically/logically hosted (e.g., is this CDN-backed, and is there any control or visibility over hosting region?) Any other security considerations typically associated with cloud-hosted content (encryption in transit and at rest, integrity verification, etc.) Is there a more detailed security/architecture document beyond the public developer documentation, or can someone from the team point us in the right direction?
1
1
313
Aug ’26
iOS 26.4 asks for Face ID instead of Screen Time passcode when disabling Screen Time access for an app
On iOS 26.4, I set a Screen Time passcode. However, when I go to Settings > Apps > [Our App] and turn off Screen Time Access for the app, the system asks for Face ID instead of the Screen Time passcode. As a result, Screen Time access can be disabled without entering the Screen Time passcode. Steps to Reproduce 1. Set a Screen Time passcode on iOS 26.4. 2. Open Settings > Apps > [Our App]. 3. Turn off Screen Time Access for the app. Expected Result The system should require the Screen Time passcode before allowing Screen Time access to be disabled. Actual Result The system asks for Face ID instead of the Screen Time passcode, and Screen Time access is disabled.
13
3
2.3k
Aug ’26
Multiple MFMessageComposeViewController
Does iOS support launching of 2 MFMessageComposeViewControllers back to back i.e without dismissing the previous one? We are integrating an SDK from a vendor who, inside the SDK is presenting the MFMessageComposeViewController 2 times back to back, and one of the MFMessageComposeViewController is getting dismissed but the other one doesn't, their standalone app does the same but it works there, not inside the SDK, Just wanted to know why the second MFMessageComposeViewController doesn't dismiss, or is it the correct approach to do so.
0
0
423
Aug ’26
PDFKit leaks a Vision document-analysis pipeline per rendered PDFDocument on iPadOS 26 – and `PDFView` already has the switch to stop it
On iPadOS 26, PDFKit runs VNRecognizeDocumentsRequest over the pages of a PDFDocument when those pages are rendered. The analysis pipelines are never released. Measured on an iPad Pro 12.9-inch 4th gen (iPad8,11), iPadOS 26.6, with a 61-page image-only scanned score: each newly-created-and-rendered PDFDocument costs about 2.7 OS threads and 20 MB, permanently. Repeatedly loading the same file from disk reached 153 threads and 1519 MB in under seven minutes, then died of an allocation failure. Nothing releases it: not replacing PDFView.document, not deallocating the PDFView entirely, not releasing the PDFDocument, and not time. With every code path in the app stopped, the thread count does not fall — it continues to rise. The stack -[PDFView visiblePagesChanged:] → +[PDFPageAnalyzerV2 analyzePage:withBox:requestTypes:] → -[VNImageRequestHandler performRequests:gatheredForensics:error:] → -[VNRecognizeDocumentsRequest internalPerformRevision:inContext:error:] → -[VNDetector processUsingQualityOfServiceClass:options:regionOfInterest:…] → -[VNControlledCapacityTasksQueue dispatchSyncByPreservingQueueCapacity:] Thread census at 1519 MB — 153 threads total, after 66 document loads: 66 PDFKit.PDFDocument.formFillingQueue 64 com.apple.VNRecognizeDocumentsRequestRevision1 10 ANEServicesThread 66 orphaned pipelines for 66 loads, all blocked on Vision's capacity limiter. The console also emits Invalid permutation index when reordering subregions. Index N must be less than number of subregions 1 continuously, with N increasing — and these keep arriving after all application activity has stopped. Isolation Each row is a separate run on the same device and OS, one variable changed. Counts are OS threads; baseline is 13. Configuration Result Page-stepping only on a stable document (~1000 visiblePagesChanged: events) No growth; footprint declines Recreating PDFThumbnailView on every load No growth Creating a PDFDocument and never rendering it No growth Creating + rendering, assigned to a PDFView +2.0 to +2.7 threads / +20 MB per load Creating + rendering, never assigned to any PDFView Same growth Creating + rendering, entire PDFView destroyed and rebuilt per load Same growth Two points worth drawing out: The leak occurs with no PDFView involved at all — plain PDFPage.thumbnail(of:for:) or PDFPage.draw(with:to:) on a freshly created document is sufficient. Destroying the PDFView releases nothing. Whatever retains the analyses outlives every object the application can reach. Also, for anyone who arrives here from the other PDFPageAnalyzerV2 threads: the usePageViewController(true, withViewOptions: nil) workaround does not help this. It reduces visiblePagesChanged: frequency, and page changes on a stable document leak nothing. The variable is newly rendered documents, not new pages. The switch already exists PDFView implements -setDocumentAnalysisEnabled: and -isDocumentAnalysisEnabled, plus -handleAnalysisCompletionOfPage:resultTypes:. None of these appear in any public header. With document analysis disabled, the leak disappears completely — 28 consecutive document loads with zero thread growth, and after stopping, the process released down to 6 threads and 64 MB, below its own idle baseline. It also suppresses the leak for documents never assigned to that PDFView, so whatever the flag gates is not scoped to a single view. For completeness, the per-page -setCandidateForOCR: / -setDidPerformOCR: accessors do not help: the writes land and read back correctly, and the analysis runs anyway. They appear to be state rather than policy. Request Either: Fix the leak — cancel and release analyses when the document or the view goes away; or Make documentAnalysisEnabled public on PDFView (or add an equivalent on PDFDocument). Ideally, please do both. The second costs Apple nothing: the property exists, it works, and it is exactly the control that is needed. Applications that render sheet music, engineering drawings, or any other content where document understanding provides no value are currently paying for it with unbounded memory growth and no supported way to decline. Filed as FB24211659. Happy to share the isolation harness with anyone from the PDFKit team. Related: 825803 (crash in PDFPageAnalyzerV2, FB22409977), 827781 (deadlock in the same class), 838272 / 837282 (PDFTileSurface over-release), 107007 (CGContextDrawPDFPage thread safety, open since 2018).
0
1
300
Aug ’26
Return journey from containing app back to original host
Question 1 (Return journey from containing app back to original host): Is there an alternative, supported method for a custom keyboard extension to launch its containing app such that when that containing app is later suspended/resigned, the system returns the user to the original host app (e.g., Notes) instead of the Home screen? Does iOS 26 provide any handoff/return APIs for the keyboard voice‑input scenario? Question 2 (Full‑access‑off persistence and settings navigation): (a) Is the shared app group container expected to be effectively read‑only (with EPERM) when Full Access is off? If so, is there any supported way to persist keyboard settings (that require writing to shared files) without Full Access? (b) What is the supported method for a keyboard extension to direct the user to Settings to enable Full Access on iOS 26, given that openURL via responder chain and extensionContext.open both fail? We are seeking a reliable, non‑private API approach.
1
0
359
Aug ’26
Bug: Correct ASSA File not fetched
How does iOS handle Associated Domains and AASA files when switching between environments? I have an iOS application that supports multiple environments (test and production). Each environment has its own domain and its own AASA file. We have an SDK that requires a domain during initialization. Based on the selected environment, we initialize the SDK with either the test domain or the production domain. We have configured the Associated Domains capability in Xcode with the required domains. However, i'm unclear about how iOS manages the AASA association in this scenario. For example: test.example.com Has its own AASA file. Used when the SDK is initialized with the test domain. example.com Has its own AASA file. Used when the SDK is initialized with the production domain. The SDK receives the domain during initialization, and we dynamically select the domain based on the environment configuration. The question is: If multiple domains are configured in Associated Domains, does iOS fetch and cache the AASA file for all configured domains when the app is installed, or only for the domain currently being used by the application? If the application switches the SDK configuration from the test domain to the production domain (or vice versa) after installation, how does iOS know that it needs to fetch the AASA file for the new domain? Is there any supported way to force iOS to re-fetch the AASA file for a newly selected associated domain? Trying to understand the correct approach for supporting multiple environments when the SDK domain is selected dynamically at runtime. If both test and production domains are configured in Associated Domains, how does iOS determine which AASA file should be used when the SDK is initialized with a specific domain (for example, test)? Does iOS fetch and validate both AASA files upfront and then check only the matching domain at runtime, or does it dynamically fetch/check only the domain provided to the SDK?
1
0
368
Aug ’26
iOS 26 Message Filter Extension not invoked after conversation is moved to Spam
We're seeing a behavior change with ILMessageFilterExtension on iOS 26 and would like to confirm whether this is expected or a regression. Environment iOS: 26.x Framework: IdentityLookup Extension type: ILMessageFilterExtension Behavior For a new sender: An incoming SMS arrives. handle(_:context:completion:) is invoked. The extension returns a classification. The conversation is moved to the Spam folder. Subsequent SMS messages in the same conversation are delivered to the Spam folder, but handle(_:context:completion:) is no longer invoked for any new messages. Expected behavior We expected the message filter extension to be invoked for every incoming SMS, regardless of the current conversation folder, allowing the extension to evaluate each message independently. Actual behavior Once the conversation is in the Spam folder, all subsequent messages bypass the extension completely. The extension receives no callback, making it impossible to: Re-evaluate new messages using updated filtering logic. Change the classification if sender reputation changes. Apply cloud-based or dynamic filtering policies on subsequent messages. Questions Is this behavior expected in iOS 26? Has the message filtering pipeline changed so that conversations already classified as Spam no longer invoke ILMessageFilterExtension? Is there any documented API or recommended approach to have the extension evaluate every incoming message for an existing Spam conversation? If this is not expected, is this a known issue? If anyone from Apple or other developers can confirm whether this is by design, it would be greatly appreciated.
1
0
457
Aug ’26
WeatherKit fails with WDSJWTAuthenticatorServiceListener.Errors Code=2
WeatherKit consistently fails with the following error: WDSJWTAuthenticatorServiceListener.Errors Code=2 This happens on a physical device regardless of the troubleshooting steps I try. After the error occurs, the app uses a third-party fallback provider successfully. The issue appears similar to failures reported by other developers on iOS 26, even though the WeatherKit entitlement and signing configuration seem valid. I have verified the following: • The signed application binary contains the WeatherKit entitlement. • The embedded provisioning profile contains the WeatherKit entitlement. • The application identifier and team identifier match the provisioning profile. • The WeatherKit capability was disabled, saved, enabled again, and saved. • Xcode automatic signing generated a new provisioning profile after resetting the capability. • The project was cleaned and a fresh build was installed on the physical device. • Both the application and the device were restarted. • Location permission is granted and the app receives valid coordinates. • Network connectivity works correctly. • A non-Apple fallback weather provider successfully returns a forecast for the same coordinates. Despite this, every WeatherKit request still fails with WDSJWTAuthenticatorServiceListener.Errors Code=2. Has anyone identified the cause of this error on iOS 17 or 26 or found an additional signing, entitlement, App ID, or provisioning step required to resolve it? Environment: • iOS version: iOS: 26.6 (23G71) • Xcode version: 26.5 • Device: iPhone 14 Pro • WeatherKit API used: WeatherService.shared • Distribution method:TestFlight
2
0
393
Aug ’26
Bug: AASA file not fetched on app install
~5% of our users when downloading the iOS application from the Apple Store for the first time are unable to enrol a Passkey and experience an error saying the application is not associated with [DOMAIN]. The error message thrown by the iOS credentials API is "The operation couldn't be completed. Application with identifier [APPID] is not associated with domain [DOMAIN]" We have raised this via the developer support portal with case id: 102315543678 Question: Why does the AASA file fail to fetch on app install and is there anything that can be done to force the app to fetch the file? Can this bug be looked at urgently as it is impacting security critical functionality? Other Debugging Observations We have confirmed that our AASA file is correctly formatted and hosted on the Apple CDN. Under normal circumstances the association is created on install and Passkey enrolment works as intended. We have observed that when customers uninstall/reinstall the app this often, but not always, resolves the issue. We also know this issue can resolve itself overtime without any intervention. We have ruled out network (e.g VPN) issues and have reproduced the issue across a number of different network configurations. We have ruled out the Keychain provider and have reproduced it across a variety of different providers and combinations of. We observed this across multiple versions of the iOS operating system and iPhone hardware including the latest hardware and iOS version.
13
3
3.7k
Aug ’26
LiveCallerId OHTTP Relay: Works in TestFlight, failing in Production (Bundle ID: no.opplysningen.bedrift.LiveCallerId)
We’ve been implementing LiveCallerId using OHTTP and have hit a wall with the production environment. The setup works perfectly in TestFlight, but the release version of the app is consistently being rejected by the Apple OHTTP Relay when trying to tunnel traffic to our gateway. Timeline & Status: Applied via the form in September 2025. Received confirmation in November 2025 that our /.well-known/ohttp-keys endpoint was correctly configured. Since then, we've struggled to get a dialogue with Apple to confirm the final production whitelisting. Technical Observations: Our ohttp-keys endpoint is being polled frequently (every few minutes). Based on the traffic, this is clearly the Apple Relay infrastructure fetching/refreshing the keys, not the devices themselves. This suggests the Relay "sees" our configuration, yet it still refuses to tunnel traffic to our gateway in the production environment. Since everything is functional in TestFlight, our implementation seems correct. It feels like there is a configuration mismatch or a missing "production flip" on the Relay side for our Bundle ID. If anyone from the Apple engineering team could verify the status for this Bundle ID, it would be a huge help. We've been stuck in this "TestFlight-only" state for quite a while now.
1
0
708
Aug ’26
Is local-time validation and re-arming a supported workaround for premature DeviceActivity thresholds on iOS 26?
I am investigating premature DeviceActivityMonitor.eventDidReachThreshold callbacks on physical devices running iOS 26.x. I have also observed similar overcounting behavior on iOS 18.x. In one repeatable test, an all-activity event configured with a 10-minute threshold fired after approximately 5 minutes of actual unlocked usage. The event was created with: A single completion threshold. includesPastActivity: false. A nonrepeating DeviceActivitySchedule. A unique activity and event identity for each monitoring generation. However, eventDidReachThreshold could still arrive significantly earlier than expected. Defensive mitigation I have been testing a defensive mechanism that treats eventDidReachThreshold only as a wake-up signal, rather than authoritative proof that the configured usage duration has elapsed. When the callback arrives, the monitor extension independently validates the duration against locally persisted timing state. The flow is: Each logical work cycle has a unique cycle identifier and generation number. The app stores a local timing anchor when monitoring begins or resumes. When the threshold callback arrives, the extension verifies: The cycle identifier. The generation number. The activity name. The current application state. The extension calculates a locally trusted elapsed duration. If the local duration has not reached the configured duration: It does not send a notification. It does not apply any user-visible action. It persists only the locally trusted progress. It increments the generation number. It stops the previous monitor. It registers a new event for only the locally remaining duration. Completion is accepted only when the locally calculated duration is due. Delayed callbacks from previous generations are ignored. Simplified pseudocode: override func eventDidReachThreshold( _ event: DeviceActivityEvent.Name, activity: DeviceActivityName ) { let state = loadPersistedState() guard eventMatchesCurrentGeneration( event: event, activity: activity, state: state ) else { // Ignore stale or duplicated callbacks. return } let now = Date() let trustedElapsed = calculateLocallyAccountedElapsed( state: state, now: now ) let tolerance: TimeInterval = 3 if trustedElapsed + tolerance < state.configuredDuration { let remaining = state.configuredDuration - trustedElapsed var nextState = state nextState.confirmedElapsed = trustedElapsed nextState.generation += 1 // Persist the new generation before replacing the monitor. persistAtomically(nextState) center.stopMonitoring([activity]) let nextActivity = makeActivityName( cycleID: nextState.cycleID, generation: nextState.generation ) let completionEvent = DeviceActivityEvent( threshold: normalizedDateComponents(remaining), includesPastActivity: false ) do { try center.startMonitoring( nextActivity, during: makeNonRepeatingSchedule(), events: [ makeCompletionEventName(nextState): completionEvent ] ) } catch { // Persist a recoverable unavailable state. recordMonitoringFailure(error) } return } transitionToCompletedState() scheduleUserNotification() } Durations are normalized before creating the event: func normalizedDateComponents( _ duration: TimeInterval ) -> DateComponents { let seconds = max(1, Int(duration)) return DateComponents( minute: seconds / 60, second: seconds % 60 ) } This avoids using values such as second: 300. Example For a configured duration of 10 minutes: DeviceActivity incorrectly delivers the completion callback after approximately 5 minutes. Local accounting reports only approximately 5 minutes. No notification or other user-visible action is performed. The previous monitor is replaced with a new generation configured for the remaining approximately 5 minutes. Completion is accepted only after the locally trusted timing state is due. This mechanism has so far prevented premature DeviceActivity callbacks from producing premature notifications during my physical-device testing on iOS 26.x. Additional precautions The implementation also uses the following precautions: Only one completion event is registered instead of multiple minute checkpoints. includesPastActivity is explicitly set to false. Every replacement monitor has a new generation identity. Generation state is persisted before the old monitor is replaced. Callbacks from an old cycle, generation, or activity name are ignored. The extension performs only small, bounded state updates. User-visible actions occur only after local validation succeeds. Limitations This is a defensive workaround, not a fix for the underlying DeviceActivity or Screen Time accounting issue. Known limitations include: It cannot prevent iOS from delivering an incorrect callback. If the system never delivers another callback, completion may be delayed or missed. If every new event immediately fires, repeated re-registration may occur. startMonitoring may fail if the system considers the activities too numerous or too tightly scheduled. Local unlocked-time accounting depends on reliable lock and unlock observations. Wall-clock calculations must consider manual system-time changes. The approach cannot correct Screen Time’s internal activity data. For modes that intentionally count locked time, absolute local-notification scheduling may be more reliable and may avoid DeviceActivity thresholds entirely. All processing in this mitigation occurs on-device. It does not require uploading activity tokens, Screen Time data, user identifiers, or diagnostic logs. The implementation uses only public APIs. Questions for Apple Is treating eventDidReachThreshold as a wake-up signal and validating it against locally persisted timing state an acceptable design? Is stopping the current monitor and registering a new generation for only the locally remaining duration from the monitor extension considered a supported recovery pattern? Are there documented or recommended limits, rate controls, or backoff requirements for this type of defensive re-registration? Is there a more reliable supported API for usage-based completion when eventDidReachThreshold fires prematurely on iOS 26? I would appreciate confirmation from Apple engineers or feedback from other developers who have tested a similar approach.
0
0
348
Aug ’26
Live Caller ID Lookup request stuck in review - how to verify our endpoints pass validation?
We submitted Live Caller ID Lookup requests for two apps and both remain “In Review.” Our PIR server, Privacy Pass issuer and OHTTP gateway are deployed, DNS TXT records are published for both bundle identifiers, and the test number returns correctly. Is there a way to verify from our side that Apple’s automated endpoint validation passes? Any common misconfiguration that causes a request to sit without feedback?
0
0
518
Aug ’26
How to observe calendar changes by using NotificationCenter.messages(of: for:)?
Overview I would like to observe calendar changes using NotificationCenter.messages(of: for:) I want receive Sendable messages, not traditional Notification which is not Sendable Problem I can't seem to get the following code to compile import EventKit NotificationCenter.default.messages( of: EKEventStore.EventStoreChanged.Subject.self, for: .changed ) Reference https://developer.apple.com/documentation/foundation/notificationcenter/messageidentifier/changed-50yz5 Questions How can I use by using NotificationCenter.messages(of: for:) for Calendar changes?
2
0
542
Aug ’26
Clarification on Declared Age Range Prompt in Texas and Brazil
Hello Apple Developer Forum, We have implemented the Declared Age Range API exactly as described in Apple's documentation. Our implementation checks isEligibleForAgeFeatures before calling requestAgeRange, as recommended. We have been testing with different users located in Texas (US) and Brazil. However, for all users, isEligibleForAgeFeatures consistently returns false, so the Declared Age Range prompt is never displayed. We would appreciate some clarification on the following: Under what conditions does isEligibleForAgeFeatures return true? When is the Declared Age Range prompt expected to be shown? Besides the user's region, are there any additional eligibility requirements, such as whether the Apple ID has a verified payment method (credit/debit card), verified identity or address, account age or a phased rollout? Since all of our test users are in supported regions (Texas and Brazil), we expected at least some users to be eligible. However, all four test accounts consistently return false. Could you please clarify how Apple determines eligibility for the Declared Age Range feature and when developers should expect the prompt to appear? Thank you for your guidance.
0
0
487
Aug ’26
Apple CDN returning 404 Not found for our universal Link domain.
Hi Team, Our universal links were working fine but since last week we are facing issues and when tapping the links outside app it takes to browser and not the app. Apple CDN is returning 404 for our domain and not the contents of AASA file. https://app-site-association.cdn-apple.com/a/v1/app.ooredoo.om sudo swcutil dl -d app.ooredoo.om returns The operation couldn’t be completed. (SWCErrorDomain error 7.) Can we get the exact issue apple is facing to cache the AASA file in CDN. Any server config which we need to do for AASA bot to access the file. Thanks in advance.
28
0
2.4k
Aug ’26
TelephonyMessagingKit drops first SMS at cold launch — race between client XPC handler registration and server pending flush
Hi all, I'm the developer of OV Message, an end-to-end encrypted SMS messaging app already shipped on Google Play (Android, where it natively encrypts SMS content). The iOS port aims to be the default carrier-messaging app, handling SMS, MMS, and RCS through TelephonyMessagingKit with the com.apple.developer.carrier-messaging-app entitlement under the EU programme. While testing the cold-launch flow on iOS 26.x, I've hit a reproducible bug that silently drops the first SMS/MMS/RCS that wakes the app, and I'd like to confirm whether other devs working with this API see the same. The bug When a default carrier-messaging app is force-killed and a message arrives, iOS correctly: Routes the message via CommCenter (IMS in my case — SFR France) Wakes the app in background (state = .background at didFinishLaunchingWithOptions) Acquires a TelephonyMessaging runningboard assertion on the app But CommCenter then pushes the pending message via XPC before the client TMK library has finished registering its messageHandlersByID dictionary. Result: client responds Received unhandled request, server logs TMKXPCError Code=2, message is dropped, never delivered to for await in incomingMessageNotifications. Subsequent messages (with the app warm) work fine. Native log sequence (from idevicesyslog with the Telephony logging profile) T+0.000 CommCenter: SMS arrives via IMS (k3GPP) T+0.003 CommCenter: Default app is set to com.example.app T+0.004 CommCenter: Attempting to launch and acquire process assertion T+0.083 CommCenter: Notifying SMS message received, target: bundleID=... T+0.085 CommCenter(TMK): There are no client connections matching, pending message [~125 ms — app boots] T+0.128 App(TMK): Configuring connection T+0.128 App(TMK): Pinging remote end T+0.130 CommCenter(TMK): Received new connection from PID T+0.130 CommCenter(TMK): New incoming connection, flushing pending messages (1) ← server flushes T+0.130 App(TMK): Received unhandled request ← client not ready T+0.131 CommCenter(TMK): Failed to send pending message: TMKXPCError Code=2 T+0.132 App(TMK): Registered for IncomingMessageNotification (smsReceived) ← ~2 ms too late The race window between Pinging remote end (client) and Registered for IncomingMessageNotification (client) is 2–7 ms across my measurements. CommCenter considers the connection ready as soon as the ping completes, but the client library populates messageHandlersByID slightly after, so the dispatch fails. Minimal reproduction I built a ~50-line Swift app to confirm this isn't specific to OV Message. UIKit AppDelegate, single for await in TelephonyMessagingSession.shared.smsService.incomingMessageNotifications started in didFinishLaunchingWithOptions. No SwiftUI, no other modules, no Darwin notifications. Just TMK. Steps: Build & install on iPhone iOS 26.x with carrier-messaging-app entitlement (auto-provisioned in iOS 26) Settings → Apps → Default Messaging → select the test app Force-kill, then send 2 SMS in rapid succession from another phone Wait 30 s, open the app — log shows only the 2nd SMS Same result: the 1st SMS is gone. I've reproduced this consistently dozens of times. Source code (Swift + xcodegen project.yml): https://gist.github.com/ovmessage/fbc529292a65222191bec6ce5e5a4275 What I've tried Task.detached(priority: .userInitiated) to decouple the for await from main thread scheduling — no effect (race is internal to TMK lib, before our scheduling) Pre-fetching cellularServices synchronously — no effect Subscribing MMS + RCS in parallel — no effect Direct XPCSession/xpc_connection_create_mach_service to com.apple.commcenter.tmk.xpc — Apple has marked these unavailable on iOS for 3rd-party apps (no public way to bypass the lib) I've also done runtime introspection of the TMK framework via Mirror, which confirms the architecture: a single XPCConnection.messageHandlersByID dict shared by smsReceived, mmsReceived, rcsReceivedNotification — all four entries (incl. serviceStatusNotification) are populated after the XPC ping. So the same race affects SMS, MMS, and RCS equally. Suggested fixes (Apple-side) Either: Server (CommCenter): defer flushing pending messages until the client confirms its handlers are registered (extra XPC handshake message) Client (TelephonyMessagingKit): register messageHandlersByID entries before sending Pinging remote end, so they exist when the server starts flushing Buffer client-side: cache messages received before handler registration completes, dispatch on attach Filed in Feedback Assistant FB[YOUR_FB_NUMBER_HERE] Question for fellow devs If you're also building with carrier-messaging-app entitlement (Beeper, Google Messages on iOS, anyone in the EU programme), can you confirm whether you see the same race? Especially interested in whether: It happens with non-IMS carriers (mine is SFR France, IMS-routed via SIP) iOS 26.1 / 26.2 changed the timing Anyone has found a workaround I haven't tried Thanks.
7
1
1.4k
Jul ’26
ImageAnalyzer running VNRecognizeTextRequest in the background?
Using VisionKit, there's two main ways to get text from images. ImageAnalyzer VNRecognizeRequest Based on some OCR tests, I'm seeing that the outputs from these two methods are different. Initially, I thought ImageAnalyzer was running VNRequestTextRecognitionLevel.fast because it's for Live Text, but the outputs from ImageAnalyzer are sometimes better than VNRequestTextRecognitionLevel.accurate. Is ImageAnalyzer running VNRequestTextRecognition in the background? Or if it isn't, what pipeline is it using to detect text?
Replies
1
Boosts
2
Views
1.1k
Activity
4w
Security architecture and asset protection for Apple-hosted Background Assets
We're evaluating Apple-hosted Background Assets for an app distributed on App Store and would like to understand the security model behind it before adopting it. So far the public documentation only mentions the HTTPS requirement for asset transport. We'd appreciate any additional documentation or guidance covering: How asset downloads are authenticated (e.g., is access tied to the app's entitlement/provisioning, or is there a separate token/credential mechanism?) How access to specific assets is controlled/scoped Where Apple-hosted assets are physically/logically hosted (e.g., is this CDN-backed, and is there any control or visibility over hosting region?) Any other security considerations typically associated with cloud-hosted content (encryption in transit and at rest, integrity verification, etc.) Is there a more detailed security/architecture document beyond the public developer documentation, or can someone from the team point us in the right direction?
Replies
1
Boosts
1
Views
313
Activity
Aug ’26
iOS 26.4 asks for Face ID instead of Screen Time passcode when disabling Screen Time access for an app
On iOS 26.4, I set a Screen Time passcode. However, when I go to Settings > Apps > [Our App] and turn off Screen Time Access for the app, the system asks for Face ID instead of the Screen Time passcode. As a result, Screen Time access can be disabled without entering the Screen Time passcode. Steps to Reproduce 1. Set a Screen Time passcode on iOS 26.4. 2. Open Settings > Apps > [Our App]. 3. Turn off Screen Time Access for the app. Expected Result The system should require the Screen Time passcode before allowing Screen Time access to be disabled. Actual Result The system asks for Face ID instead of the Screen Time passcode, and Screen Time access is disabled.
Replies
13
Boosts
3
Views
2.3k
Activity
Aug ’26
Multiple MFMessageComposeViewController
Does iOS support launching of 2 MFMessageComposeViewControllers back to back i.e without dismissing the previous one? We are integrating an SDK from a vendor who, inside the SDK is presenting the MFMessageComposeViewController 2 times back to back, and one of the MFMessageComposeViewController is getting dismissed but the other one doesn't, their standalone app does the same but it works there, not inside the SDK, Just wanted to know why the second MFMessageComposeViewController doesn't dismiss, or is it the correct approach to do so.
Replies
0
Boosts
0
Views
423
Activity
Aug ’26
My App is crashing at launch and it’s on App Store
I recently had my app Spark Matched: https://apps.apple.com/us/app/spark-matched/id6786071027 accepted to the Apple Store but when I try to launch promptly closes and the icon I added isn’t displaying
Replies
4
Boosts
0
Views
526
Activity
Aug ’26
PDFKit leaks a Vision document-analysis pipeline per rendered PDFDocument on iPadOS 26 – and `PDFView` already has the switch to stop it
On iPadOS 26, PDFKit runs VNRecognizeDocumentsRequest over the pages of a PDFDocument when those pages are rendered. The analysis pipelines are never released. Measured on an iPad Pro 12.9-inch 4th gen (iPad8,11), iPadOS 26.6, with a 61-page image-only scanned score: each newly-created-and-rendered PDFDocument costs about 2.7 OS threads and 20 MB, permanently. Repeatedly loading the same file from disk reached 153 threads and 1519 MB in under seven minutes, then died of an allocation failure. Nothing releases it: not replacing PDFView.document, not deallocating the PDFView entirely, not releasing the PDFDocument, and not time. With every code path in the app stopped, the thread count does not fall — it continues to rise. The stack -[PDFView visiblePagesChanged:] → +[PDFPageAnalyzerV2 analyzePage:withBox:requestTypes:] → -[VNImageRequestHandler performRequests:gatheredForensics:error:] → -[VNRecognizeDocumentsRequest internalPerformRevision:inContext:error:] → -[VNDetector processUsingQualityOfServiceClass:options:regionOfInterest:…] → -[VNControlledCapacityTasksQueue dispatchSyncByPreservingQueueCapacity:] Thread census at 1519 MB — 153 threads total, after 66 document loads: 66 PDFKit.PDFDocument.formFillingQueue 64 com.apple.VNRecognizeDocumentsRequestRevision1 10 ANEServicesThread 66 orphaned pipelines for 66 loads, all blocked on Vision's capacity limiter. The console also emits Invalid permutation index when reordering subregions. Index N must be less than number of subregions 1 continuously, with N increasing — and these keep arriving after all application activity has stopped. Isolation Each row is a separate run on the same device and OS, one variable changed. Counts are OS threads; baseline is 13. Configuration Result Page-stepping only on a stable document (~1000 visiblePagesChanged: events) No growth; footprint declines Recreating PDFThumbnailView on every load No growth Creating a PDFDocument and never rendering it No growth Creating + rendering, assigned to a PDFView +2.0 to +2.7 threads / +20 MB per load Creating + rendering, never assigned to any PDFView Same growth Creating + rendering, entire PDFView destroyed and rebuilt per load Same growth Two points worth drawing out: The leak occurs with no PDFView involved at all — plain PDFPage.thumbnail(of:for:) or PDFPage.draw(with:to:) on a freshly created document is sufficient. Destroying the PDFView releases nothing. Whatever retains the analyses outlives every object the application can reach. Also, for anyone who arrives here from the other PDFPageAnalyzerV2 threads: the usePageViewController(true, withViewOptions: nil) workaround does not help this. It reduces visiblePagesChanged: frequency, and page changes on a stable document leak nothing. The variable is newly rendered documents, not new pages. The switch already exists PDFView implements -setDocumentAnalysisEnabled: and -isDocumentAnalysisEnabled, plus -handleAnalysisCompletionOfPage:resultTypes:. None of these appear in any public header. With document analysis disabled, the leak disappears completely — 28 consecutive document loads with zero thread growth, and after stopping, the process released down to 6 threads and 64 MB, below its own idle baseline. It also suppresses the leak for documents never assigned to that PDFView, so whatever the flag gates is not scoped to a single view. For completeness, the per-page -setCandidateForOCR: / -setDidPerformOCR: accessors do not help: the writes land and read back correctly, and the analysis runs anyway. They appear to be state rather than policy. Request Either: Fix the leak — cancel and release analyses when the document or the view goes away; or Make documentAnalysisEnabled public on PDFView (or add an equivalent on PDFDocument). Ideally, please do both. The second costs Apple nothing: the property exists, it works, and it is exactly the control that is needed. Applications that render sheet music, engineering drawings, or any other content where document understanding provides no value are currently paying for it with unbounded memory growth and no supported way to decline. Filed as FB24211659. Happy to share the isolation harness with anyone from the PDFKit team. Related: 825803 (crash in PDFPageAnalyzerV2, FB22409977), 827781 (deadlock in the same class), 838272 / 837282 (PDFTileSurface over-release), 107007 (CGContextDrawPDFPage thread safety, open since 2018).
Replies
0
Boosts
1
Views
300
Activity
Aug ’26
Return journey from containing app back to original host
Question 1 (Return journey from containing app back to original host): Is there an alternative, supported method for a custom keyboard extension to launch its containing app such that when that containing app is later suspended/resigned, the system returns the user to the original host app (e.g., Notes) instead of the Home screen? Does iOS 26 provide any handoff/return APIs for the keyboard voice‑input scenario? Question 2 (Full‑access‑off persistence and settings navigation): (a) Is the shared app group container expected to be effectively read‑only (with EPERM) when Full Access is off? If so, is there any supported way to persist keyboard settings (that require writing to shared files) without Full Access? (b) What is the supported method for a keyboard extension to direct the user to Settings to enable Full Access on iOS 26, given that openURL via responder chain and extensionContext.open both fail? We are seeking a reliable, non‑private API approach.
Replies
1
Boosts
0
Views
359
Activity
Aug ’26
Bug: Correct ASSA File not fetched
How does iOS handle Associated Domains and AASA files when switching between environments? I have an iOS application that supports multiple environments (test and production). Each environment has its own domain and its own AASA file. We have an SDK that requires a domain during initialization. Based on the selected environment, we initialize the SDK with either the test domain or the production domain. We have configured the Associated Domains capability in Xcode with the required domains. However, i'm unclear about how iOS manages the AASA association in this scenario. For example: test.example.com Has its own AASA file. Used when the SDK is initialized with the test domain. example.com Has its own AASA file. Used when the SDK is initialized with the production domain. The SDK receives the domain during initialization, and we dynamically select the domain based on the environment configuration. The question is: If multiple domains are configured in Associated Domains, does iOS fetch and cache the AASA file for all configured domains when the app is installed, or only for the domain currently being used by the application? If the application switches the SDK configuration from the test domain to the production domain (or vice versa) after installation, how does iOS know that it needs to fetch the AASA file for the new domain? Is there any supported way to force iOS to re-fetch the AASA file for a newly selected associated domain? Trying to understand the correct approach for supporting multiple environments when the SDK domain is selected dynamically at runtime. If both test and production domains are configured in Associated Domains, how does iOS determine which AASA file should be used when the SDK is initialized with a specific domain (for example, test)? Does iOS fetch and validate both AASA files upfront and then check only the matching domain at runtime, or does it dynamically fetch/check only the domain provided to the SDK?
Replies
1
Boosts
0
Views
368
Activity
Aug ’26
iOS 26 Message Filter Extension not invoked after conversation is moved to Spam
We're seeing a behavior change with ILMessageFilterExtension on iOS 26 and would like to confirm whether this is expected or a regression. Environment iOS: 26.x Framework: IdentityLookup Extension type: ILMessageFilterExtension Behavior For a new sender: An incoming SMS arrives. handle(_:context:completion:) is invoked. The extension returns a classification. The conversation is moved to the Spam folder. Subsequent SMS messages in the same conversation are delivered to the Spam folder, but handle(_:context:completion:) is no longer invoked for any new messages. Expected behavior We expected the message filter extension to be invoked for every incoming SMS, regardless of the current conversation folder, allowing the extension to evaluate each message independently. Actual behavior Once the conversation is in the Spam folder, all subsequent messages bypass the extension completely. The extension receives no callback, making it impossible to: Re-evaluate new messages using updated filtering logic. Change the classification if sender reputation changes. Apply cloud-based or dynamic filtering policies on subsequent messages. Questions Is this behavior expected in iOS 26? Has the message filtering pipeline changed so that conversations already classified as Spam no longer invoke ILMessageFilterExtension? Is there any documented API or recommended approach to have the extension evaluate every incoming message for an existing Spam conversation? If this is not expected, is this a known issue? If anyone from Apple or other developers can confirm whether this is by design, it would be greatly appreciated.
Replies
1
Boosts
0
Views
457
Activity
Aug ’26
WeatherKit fails with WDSJWTAuthenticatorServiceListener.Errors Code=2
WeatherKit consistently fails with the following error: WDSJWTAuthenticatorServiceListener.Errors Code=2 This happens on a physical device regardless of the troubleshooting steps I try. After the error occurs, the app uses a third-party fallback provider successfully. The issue appears similar to failures reported by other developers on iOS 26, even though the WeatherKit entitlement and signing configuration seem valid. I have verified the following: • The signed application binary contains the WeatherKit entitlement. • The embedded provisioning profile contains the WeatherKit entitlement. • The application identifier and team identifier match the provisioning profile. • The WeatherKit capability was disabled, saved, enabled again, and saved. • Xcode automatic signing generated a new provisioning profile after resetting the capability. • The project was cleaned and a fresh build was installed on the physical device. • Both the application and the device were restarted. • Location permission is granted and the app receives valid coordinates. • Network connectivity works correctly. • A non-Apple fallback weather provider successfully returns a forecast for the same coordinates. Despite this, every WeatherKit request still fails with WDSJWTAuthenticatorServiceListener.Errors Code=2. Has anyone identified the cause of this error on iOS 17 or 26 or found an additional signing, entitlement, App ID, or provisioning step required to resolve it? Environment: • iOS version: iOS: 26.6 (23G71) • Xcode version: 26.5 • Device: iPhone 14 Pro • WeatherKit API used: WeatherService.shared • Distribution method:TestFlight
Replies
2
Boosts
0
Views
393
Activity
Aug ’26
Crash Report - What may have been the cause?
See crash details here:- https://pastebin.com/i9u5PE4X There's a comprehensive thread here, folks! https://discussions.apple.com/thread/255651156?sortBy=oldest_first Thanks for any thoughts.
Replies
12
Boosts
0
Views
2.2k
Activity
Aug ’26
Bug: AASA file not fetched on app install
~5% of our users when downloading the iOS application from the Apple Store for the first time are unable to enrol a Passkey and experience an error saying the application is not associated with [DOMAIN]. The error message thrown by the iOS credentials API is "The operation couldn't be completed. Application with identifier [APPID] is not associated with domain [DOMAIN]" We have raised this via the developer support portal with case id: 102315543678 Question: Why does the AASA file fail to fetch on app install and is there anything that can be done to force the app to fetch the file? Can this bug be looked at urgently as it is impacting security critical functionality? Other Debugging Observations We have confirmed that our AASA file is correctly formatted and hosted on the Apple CDN. Under normal circumstances the association is created on install and Passkey enrolment works as intended. We have observed that when customers uninstall/reinstall the app this often, but not always, resolves the issue. We also know this issue can resolve itself overtime without any intervention. We have ruled out network (e.g VPN) issues and have reproduced the issue across a number of different network configurations. We have ruled out the Keychain provider and have reproduced it across a variety of different providers and combinations of. We observed this across multiple versions of the iOS operating system and iPhone hardware including the latest hardware and iOS version.
Replies
13
Boosts
3
Views
3.7k
Activity
Aug ’26
LiveCallerId OHTTP Relay: Works in TestFlight, failing in Production (Bundle ID: no.opplysningen.bedrift.LiveCallerId)
We’ve been implementing LiveCallerId using OHTTP and have hit a wall with the production environment. The setup works perfectly in TestFlight, but the release version of the app is consistently being rejected by the Apple OHTTP Relay when trying to tunnel traffic to our gateway. Timeline & Status: Applied via the form in September 2025. Received confirmation in November 2025 that our /.well-known/ohttp-keys endpoint was correctly configured. Since then, we've struggled to get a dialogue with Apple to confirm the final production whitelisting. Technical Observations: Our ohttp-keys endpoint is being polled frequently (every few minutes). Based on the traffic, this is clearly the Apple Relay infrastructure fetching/refreshing the keys, not the devices themselves. This suggests the Relay "sees" our configuration, yet it still refuses to tunnel traffic to our gateway in the production environment. Since everything is functional in TestFlight, our implementation seems correct. It feels like there is a configuration mismatch or a missing "production flip" on the Relay side for our Bundle ID. If anyone from the Apple engineering team could verify the status for this Bundle ID, it would be a huge help. We've been stuck in this "TestFlight-only" state for quite a while now.
Replies
1
Boosts
0
Views
708
Activity
Aug ’26
Is local-time validation and re-arming a supported workaround for premature DeviceActivity thresholds on iOS 26?
I am investigating premature DeviceActivityMonitor.eventDidReachThreshold callbacks on physical devices running iOS 26.x. I have also observed similar overcounting behavior on iOS 18.x. In one repeatable test, an all-activity event configured with a 10-minute threshold fired after approximately 5 minutes of actual unlocked usage. The event was created with: A single completion threshold. includesPastActivity: false. A nonrepeating DeviceActivitySchedule. A unique activity and event identity for each monitoring generation. However, eventDidReachThreshold could still arrive significantly earlier than expected. Defensive mitigation I have been testing a defensive mechanism that treats eventDidReachThreshold only as a wake-up signal, rather than authoritative proof that the configured usage duration has elapsed. When the callback arrives, the monitor extension independently validates the duration against locally persisted timing state. The flow is: Each logical work cycle has a unique cycle identifier and generation number. The app stores a local timing anchor when monitoring begins or resumes. When the threshold callback arrives, the extension verifies: The cycle identifier. The generation number. The activity name. The current application state. The extension calculates a locally trusted elapsed duration. If the local duration has not reached the configured duration: It does not send a notification. It does not apply any user-visible action. It persists only the locally trusted progress. It increments the generation number. It stops the previous monitor. It registers a new event for only the locally remaining duration. Completion is accepted only when the locally calculated duration is due. Delayed callbacks from previous generations are ignored. Simplified pseudocode: override func eventDidReachThreshold( _ event: DeviceActivityEvent.Name, activity: DeviceActivityName ) { let state = loadPersistedState() guard eventMatchesCurrentGeneration( event: event, activity: activity, state: state ) else { // Ignore stale or duplicated callbacks. return } let now = Date() let trustedElapsed = calculateLocallyAccountedElapsed( state: state, now: now ) let tolerance: TimeInterval = 3 if trustedElapsed + tolerance < state.configuredDuration { let remaining = state.configuredDuration - trustedElapsed var nextState = state nextState.confirmedElapsed = trustedElapsed nextState.generation += 1 // Persist the new generation before replacing the monitor. persistAtomically(nextState) center.stopMonitoring([activity]) let nextActivity = makeActivityName( cycleID: nextState.cycleID, generation: nextState.generation ) let completionEvent = DeviceActivityEvent( threshold: normalizedDateComponents(remaining), includesPastActivity: false ) do { try center.startMonitoring( nextActivity, during: makeNonRepeatingSchedule(), events: [ makeCompletionEventName(nextState): completionEvent ] ) } catch { // Persist a recoverable unavailable state. recordMonitoringFailure(error) } return } transitionToCompletedState() scheduleUserNotification() } Durations are normalized before creating the event: func normalizedDateComponents( _ duration: TimeInterval ) -> DateComponents { let seconds = max(1, Int(duration)) return DateComponents( minute: seconds / 60, second: seconds % 60 ) } This avoids using values such as second: 300. Example For a configured duration of 10 minutes: DeviceActivity incorrectly delivers the completion callback after approximately 5 minutes. Local accounting reports only approximately 5 minutes. No notification or other user-visible action is performed. The previous monitor is replaced with a new generation configured for the remaining approximately 5 minutes. Completion is accepted only after the locally trusted timing state is due. This mechanism has so far prevented premature DeviceActivity callbacks from producing premature notifications during my physical-device testing on iOS 26.x. Additional precautions The implementation also uses the following precautions: Only one completion event is registered instead of multiple minute checkpoints. includesPastActivity is explicitly set to false. Every replacement monitor has a new generation identity. Generation state is persisted before the old monitor is replaced. Callbacks from an old cycle, generation, or activity name are ignored. The extension performs only small, bounded state updates. User-visible actions occur only after local validation succeeds. Limitations This is a defensive workaround, not a fix for the underlying DeviceActivity or Screen Time accounting issue. Known limitations include: It cannot prevent iOS from delivering an incorrect callback. If the system never delivers another callback, completion may be delayed or missed. If every new event immediately fires, repeated re-registration may occur. startMonitoring may fail if the system considers the activities too numerous or too tightly scheduled. Local unlocked-time accounting depends on reliable lock and unlock observations. Wall-clock calculations must consider manual system-time changes. The approach cannot correct Screen Time’s internal activity data. For modes that intentionally count locked time, absolute local-notification scheduling may be more reliable and may avoid DeviceActivity thresholds entirely. All processing in this mitigation occurs on-device. It does not require uploading activity tokens, Screen Time data, user identifiers, or diagnostic logs. The implementation uses only public APIs. Questions for Apple Is treating eventDidReachThreshold as a wake-up signal and validating it against locally persisted timing state an acceptable design? Is stopping the current monitor and registering a new generation for only the locally remaining duration from the monitor extension considered a supported recovery pattern? Are there documented or recommended limits, rate controls, or backoff requirements for this type of defensive re-registration? Is there a more reliable supported API for usage-based completion when eventDidReachThreshold fires prematurely on iOS 26? I would appreciate confirmation from Apple engineers or feedback from other developers who have tested a similar approach.
Replies
0
Boosts
0
Views
348
Activity
Aug ’26
Live Caller ID Lookup request stuck in review - how to verify our endpoints pass validation?
We submitted Live Caller ID Lookup requests for two apps and both remain “In Review.” Our PIR server, Privacy Pass issuer and OHTTP gateway are deployed, DNS TXT records are published for both bundle identifiers, and the test number returns correctly. Is there a way to verify from our side that Apple’s automated endpoint validation passes? Any common misconfiguration that causes a request to sit without feedback?
Replies
0
Boosts
0
Views
518
Activity
Aug ’26
VPN causes CarPlay to not work
Configuring a VPN with includeAllNetworks causes CarPlay / Netflix Cast. Even enabling excludeLocalNetworks does not resolve this issue. Is this a known issue and can we work around this?
Replies
6
Boosts
0
Views
2k
Activity
Aug ’26
How to observe calendar changes by using NotificationCenter.messages(of: for:)?
Overview I would like to observe calendar changes using NotificationCenter.messages(of: for:) I want receive Sendable messages, not traditional Notification which is not Sendable Problem I can't seem to get the following code to compile import EventKit NotificationCenter.default.messages( of: EKEventStore.EventStoreChanged.Subject.self, for: .changed ) Reference https://developer.apple.com/documentation/foundation/notificationcenter/messageidentifier/changed-50yz5 Questions How can I use by using NotificationCenter.messages(of: for:) for Calendar changes?
Replies
2
Boosts
0
Views
542
Activity
Aug ’26
Clarification on Declared Age Range Prompt in Texas and Brazil
Hello Apple Developer Forum, We have implemented the Declared Age Range API exactly as described in Apple's documentation. Our implementation checks isEligibleForAgeFeatures before calling requestAgeRange, as recommended. We have been testing with different users located in Texas (US) and Brazil. However, for all users, isEligibleForAgeFeatures consistently returns false, so the Declared Age Range prompt is never displayed. We would appreciate some clarification on the following: Under what conditions does isEligibleForAgeFeatures return true? When is the Declared Age Range prompt expected to be shown? Besides the user's region, are there any additional eligibility requirements, such as whether the Apple ID has a verified payment method (credit/debit card), verified identity or address, account age or a phased rollout? Since all of our test users are in supported regions (Texas and Brazil), we expected at least some users to be eligible. However, all four test accounts consistently return false. Could you please clarify how Apple determines eligibility for the Declared Age Range feature and when developers should expect the prompt to appear? Thank you for your guidance.
Replies
0
Boosts
0
Views
487
Activity
Aug ’26
Apple CDN returning 404 Not found for our universal Link domain.
Hi Team, Our universal links were working fine but since last week we are facing issues and when tapping the links outside app it takes to browser and not the app. Apple CDN is returning 404 for our domain and not the contents of AASA file. https://app-site-association.cdn-apple.com/a/v1/app.ooredoo.om sudo swcutil dl -d app.ooredoo.om returns The operation couldn’t be completed. (SWCErrorDomain error 7.) Can we get the exact issue apple is facing to cache the AASA file in CDN. Any server config which we need to do for AASA bot to access the file. Thanks in advance.
Replies
28
Boosts
0
Views
2.4k
Activity
Aug ’26
TelephonyMessagingKit drops first SMS at cold launch — race between client XPC handler registration and server pending flush
Hi all, I'm the developer of OV Message, an end-to-end encrypted SMS messaging app already shipped on Google Play (Android, where it natively encrypts SMS content). The iOS port aims to be the default carrier-messaging app, handling SMS, MMS, and RCS through TelephonyMessagingKit with the com.apple.developer.carrier-messaging-app entitlement under the EU programme. While testing the cold-launch flow on iOS 26.x, I've hit a reproducible bug that silently drops the first SMS/MMS/RCS that wakes the app, and I'd like to confirm whether other devs working with this API see the same. The bug When a default carrier-messaging app is force-killed and a message arrives, iOS correctly: Routes the message via CommCenter (IMS in my case — SFR France) Wakes the app in background (state = .background at didFinishLaunchingWithOptions) Acquires a TelephonyMessaging runningboard assertion on the app But CommCenter then pushes the pending message via XPC before the client TMK library has finished registering its messageHandlersByID dictionary. Result: client responds Received unhandled request, server logs TMKXPCError Code=2, message is dropped, never delivered to for await in incomingMessageNotifications. Subsequent messages (with the app warm) work fine. Native log sequence (from idevicesyslog with the Telephony logging profile) T+0.000 CommCenter: SMS arrives via IMS (k3GPP) T+0.003 CommCenter: Default app is set to com.example.app T+0.004 CommCenter: Attempting to launch and acquire process assertion T+0.083 CommCenter: Notifying SMS message received, target: bundleID=... T+0.085 CommCenter(TMK): There are no client connections matching, pending message [~125 ms — app boots] T+0.128 App(TMK): Configuring connection T+0.128 App(TMK): Pinging remote end T+0.130 CommCenter(TMK): Received new connection from PID T+0.130 CommCenter(TMK): New incoming connection, flushing pending messages (1) ← server flushes T+0.130 App(TMK): Received unhandled request ← client not ready T+0.131 CommCenter(TMK): Failed to send pending message: TMKXPCError Code=2 T+0.132 App(TMK): Registered for IncomingMessageNotification (smsReceived) ← ~2 ms too late The race window between Pinging remote end (client) and Registered for IncomingMessageNotification (client) is 2–7 ms across my measurements. CommCenter considers the connection ready as soon as the ping completes, but the client library populates messageHandlersByID slightly after, so the dispatch fails. Minimal reproduction I built a ~50-line Swift app to confirm this isn't specific to OV Message. UIKit AppDelegate, single for await in TelephonyMessagingSession.shared.smsService.incomingMessageNotifications started in didFinishLaunchingWithOptions. No SwiftUI, no other modules, no Darwin notifications. Just TMK. Steps: Build & install on iPhone iOS 26.x with carrier-messaging-app entitlement (auto-provisioned in iOS 26) Settings → Apps → Default Messaging → select the test app Force-kill, then send 2 SMS in rapid succession from another phone Wait 30 s, open the app — log shows only the 2nd SMS Same result: the 1st SMS is gone. I've reproduced this consistently dozens of times. Source code (Swift + xcodegen project.yml): https://gist.github.com/ovmessage/fbc529292a65222191bec6ce5e5a4275 What I've tried Task.detached(priority: .userInitiated) to decouple the for await from main thread scheduling — no effect (race is internal to TMK lib, before our scheduling) Pre-fetching cellularServices synchronously — no effect Subscribing MMS + RCS in parallel — no effect Direct XPCSession/xpc_connection_create_mach_service to com.apple.commcenter.tmk.xpc — Apple has marked these unavailable on iOS for 3rd-party apps (no public way to bypass the lib) I've also done runtime introspection of the TMK framework via Mirror, which confirms the architecture: a single XPCConnection.messageHandlersByID dict shared by smsReceived, mmsReceived, rcsReceivedNotification — all four entries (incl. serviceStatusNotification) are populated after the XPC ping. So the same race affects SMS, MMS, and RCS equally. Suggested fixes (Apple-side) Either: Server (CommCenter): defer flushing pending messages until the client confirms its handlers are registered (extra XPC handshake message) Client (TelephonyMessagingKit): register messageHandlersByID entries before sending Pinging remote end, so they exist when the server starts flushing Buffer client-side: cache messages received before handler registration completes, dispatch on attach Filed in Feedback Assistant FB[YOUR_FB_NUMBER_HERE] Question for fellow devs If you're also building with carrier-messaging-app entitlement (Beeper, Google Messages on iOS, anyone in the EU programme), can you confirm whether you see the same race? Especially interested in whether: It happens with non-IMS carriers (mine is SFR France, IMS-routed via SIP) iOS 26.1 / 26.2 changed the timing Anyone has found a workaround I haven't tried Thanks.
Replies
7
Boosts
1
Views
1.4k
Activity
Jul ’26