Post

Replies

Boosts

Views

Activity

Reply to GKMatch: GameKitServices crashes in GCKSessionReceiveDOOB on the second real-time match — the finished session is never reclaimed
Follow-up after a night of experiments, in case it saves someone the same night. Short version: the GKMatch object itself is released fine; what leaks is held from the C side of GameKitServices, and nothing an app can do — public or private — releases it or stops the crash. Details below, all measured on the same iPhone 15 Pro / iOS 27.0 (24A435) pair of devices. THE GKMATCH IS DEALLOCATED. THE SESSION IS NOT. A weak reference to the GKMatch reads nil within 3 seconds of disconnect(), whatever the call order (delegate nil'd before or after disconnect, Apple's sample order, no disconnect() at all, GKMatchmaker.cancel() afterwards). The gcksession.recvproc / sendproc thread pair stays. So there is no application-side retain of the match to look for. WHAT IS UNDER A GKMATCH ON iOS 27 Read by reflection on the device (class_copyIvarList on the live objects), because the macOS layout is different: GKMatch._transport = GKCompositeTransport ._viceroyTransport = GKViceroyTransport ._connection = GKConnectionInternal (owns the C session and the CDXClient) .cdxClient = CDXClient -> .delegate = GKConnectionInternal ._eventDelegate = GKSessionInternal ._session = GKViceroySession -> ._session = GKSessionInternal ._relay = GKViceroyRelay ._fastSyncTransport = FastSyncTransport (new, Swift) WHAT SURVIVES, AND WHAT DOES NOT HELP After disconnect(), sending disconnectFromAllPeers to the GKSessionInternal, stopHolePunchTimer / stopListeningOnSockets / invalidate to the CDXClient, preRelease to the GKConnectionInternal, then nil'ing every back-reference between them (session -> delegate/privateDelegate/dataReceiveHandler/connection, connection -> eventDelegate/cdxClient, cdxClient -> delegate_, transport -> session/connection/relay), cancelling the remaining dispatch sources and setting _stopHandlingEvents / _shutdown: GKViceroyTransport: released GKConnectionInternal: ALIVE, retain count stable at 4 (+1 for the reading) CDXClient: ALIVE, retain count stable at 4 GKSessionInternal: ALIVE, retain count stable at 3 recvproc/sendproc pair: still running Those owners are not ivars and not dispatch sources. They sit across the C boundary: the GCKSession holds its Objective-C contexts, and it would only be destroyed in their dealloc. GameKitServices exports 51 symbols and no GCKSession* function, so there is nothing to call. THE NETWORK SIDE IS NOT THE CHANNEL EITHER GameKit does close the finished session's own sockets (:16402) at disconnect(). The one UDP socket it leaves open is the relay client's — one unconnected socket on an ephemeral port, through which the leaked CDXClient keeps punching its hole every 30 s. Replacing that descriptor in place with a UDP socket connected to the discard port (dup2, so the fd number stays taken) 15 s before the next search: match forms normally, and crashes identically. (Do not close() it: the leaked client keeps sending on that fd number every 30 s, onto whatever socket gets it next — and a sweep that is not snapshotted at teardown time will close the next search's own relay socket, which then never connects.) THE TRIGGER IS THE C-LEVEL ICE RETRY, ON A FIXED CLOCK The crash lands 14–21 s after the second match starts exchanging data, never earlier — and a second match that is quit before that never crashes (four in a row, no crash). In the unified log the sequence is: bind -> 0.3 s later "packet-from-unknown-session" on the new CDXClient -> "ICEStopConnectivityCheck() found no ICE check with call id" -> connected anyway -> ~14 s -> tellDelegate_didReceiveBand_RetryICE -> CFRetain(1). Switching off the transport health monitor on both peers at connection (stopMonitoringAll, GKTransportContext.healthMonitorEnabled = NO, _healthMonitor nil'd — all confirmed to land) changes nothing, so the retry is not the monitor's; it comes from gckSessionCheckPendingConnections itself (iDDsExpected=1 is logged unsatisfied both times). WHERE THAT LEAVES AN APP One real-time match per process on iOS 27, detected at runtime by counting gcksession.recvproc threads (task_threads + pthread_getname_np) rather than by OS version, so it stops firing the day the leak is fixed. Everything above is in FB24789094. If anyone from GameKit reads this: the leak is visible in any app that plays two real-time matches in one launch, and the crash needs the second one to live past its first ICE retry. Happy to run anything you want on these devices.
Topic: Graphics & Games SubTopic: GameKit Tags:
2d
Reply to iOS 18.4 - HomeKit actions from AppIntent fail when triggered from Widget
I’ve finally resolved this issue after many hours of debugging — posting the full solution here in case it helps others. ✅ Problem Since iOS 18.4, calling HomeKit APIs (like toggling accessories) from an AppIntent triggered by a Widget fails with the following error: Error Domain=HMErrorDomain Code=80 "Missing entitlement for API." UserInfo={ NSLocalizedFailureReason=Handler does not support background access, NSLocalizedDescription=Missing entitlement for API. } This happens only when the intent runs inside the widget process, not when it runs in the main app (even in background). ✅ Solution Part 1: Force AppIntent to run in main app process To bypass the limitations of the widget process, I made my AppIntent run in the main app instead, using the ForegroundContinuableIntent protocol. You can do this by adding the following extension: @available(iOSApplicationExtension, unavailable) extension MyActionIntent: ForegroundContinuableIntent {} Then declare your AppIntent as usual: struct MyActionIntent: AppIntent { init() {} static var openAppWhenRun: Bool { return false // Keep this false to avoid full app UI presentation } func perform() async throws -> some IntentResult { // Call HomeKit APIs here return .result() } } With this, even when triggered from a widget, the intent runs in the app's process — which has proper entitlements and access to HomeKit. 🧨 BUT... another hidden problem was causing crashes After applying the above fix, the intent still didn't seem to work — or worse, the app was crashing silently when launched in background. After deeper investigation, I found the real cause: I had a SwiftUI .backgroundTask(.appRefresh("MyBGTaskID")) { ... } modifier declared on the WindowGroup. Apparently, when the app is launched in background by an AppIntent, this SwiftUI modifier behaves incorrectly — the background task is not properly registered, and causes a crash when triggered. But this crash is invisible if you test by launching the app manually — because in that case, everything works fine, and the .backgroundTask behaves normally. ✅ Solution Part 2: Register background task manually I fixed this issue by removing the SwiftUI .backgroundTask modifier and manually registering the background task the "classic" way, in the init() of the @main app struct: import BackgroundTasks @main struct MyApp: App { init() { BGTaskScheduler.shared.register(forTaskWithIdentifier: "MyBGTaskID", using: nil) { task in // Handle your task here } } var body: some Scene { WindowGroup { ContentView() } } } ✅ Summary iOS 18.4 introduced stricter sandboxing for AppIntents running inside Widgets. Use ForegroundContinuableIntent to force your AppIntent to run in the main app context (where HomeKit works). Beware of SwiftUI .backgroundTask modifiers — they may cause background crashes when the app is launched by an AppIntent. Use manual registration via BGTaskScheduler.shared.register(...) instead. Let me know if anyone else experienced the same issue, or if you found a better way to debug background crashes in SwiftUI contexts. Hope this helps! 🙌
Apr ’25
Reply to Widgets: Detect StandBy night mode iOS 17
OK! I have found solution by myself using the showsWidgetContainerBackground Environment Value. I don't detect directly the StandBy mode but I detect that the WidgetContainerBackground has been removed. In widgetRenderingMode fullColor that means its the StandBy mode. At least it's true currently in iOS 17.0 @Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground @Environment(\.widgetRenderingMode) var widgetRenderingMode ... ZStack { // If ContainerBackground will be removed, show the light background if (!showsWidgetContainerBackground && widgetRenderingMode == .fullColor) { Color.white.opacity(0.1).cornerRadius(cornerRadius) } WidgetContentView() .containerBackground(for: .widget) { backgroundView(viewSize: panelSize) } }
Topic: App & System Services SubTopic: Core OS Tags:
Aug ’23
Reply to How in interactive widgets in ios 17 to prevent the opening of the application by clicking on the widget?
I have still exactly the same behavior on iOS 17 beta 4. It is absolutely unpredictable when the tap on an interactive item (button or toggle) will pass through and will open the app. I did put a full size interactive background button (with an intent) doing nothing to try to catch missed click. It improve behavior but some tap still open the app with no reason. It looks like a bug but I am afraid it will persist for a while... :(
Topic: App & System Services SubTopic: Core OS Tags:
Aug ’23
Reply to How to prevent ios17 interactive widgets to open the app after an interaction?
Hi! I have still exactly the same behavior on iOS 17 beta 4. It is absolutely unpredictable when the tap on an interactive item (button or toggle) will pass through and will open the app. I did put a background interactive button (with an intent) doing nothing to try to catch miss click. It improve behavior but some tap still open the app with no reason. It looks like a bug but I am afraid it will persist for a while... :(
Topic: App & System Services SubTopic: Core OS Tags:
Aug ’23
Reply to What does WIDGET_BACKGROUND_API_ADOPTION_PROMPT mean?
So same issue here. I missed a log message in the console: The widget background view is missing. Please ensure that you have called the `containerBackground(for: .widget) {…}` modifier in your widget view. Just add the new .containerBackground(for:) in your widget view and it will resolve the issue. https://developer.apple.com/videos/play/wwdc2023/10027?time=180
Jun ’23
Reply to iPhone 14 Pro (and 14 Pro Max) Native Screen Size
Thanks to geoffhackworth (https://twitter.com/geoffhackworth) it seems that Xcode-14 TestFlight builds are treated as Xcode 13 builds and are scaled to the 12/13 Pro layout. So the issue will only occurs for TestFlight build. Thank you geoffhackworth (https://twitter.com/geoffhackworth) More about this here: https://twitter.com/geoffhackworth/status/1573652281848905728
Topic: UI Frameworks SubTopic: UIKit Tags:
Sep ’22
Reply to GKMatch: GameKitServices crashes in GCKSessionReceiveDOOB on the second real-time match — the finished session is never reclaimed
Follow-up after a night of experiments, in case it saves someone the same night. Short version: the GKMatch object itself is released fine; what leaks is held from the C side of GameKitServices, and nothing an app can do — public or private — releases it or stops the crash. Details below, all measured on the same iPhone 15 Pro / iOS 27.0 (24A435) pair of devices. THE GKMATCH IS DEALLOCATED. THE SESSION IS NOT. A weak reference to the GKMatch reads nil within 3 seconds of disconnect(), whatever the call order (delegate nil'd before or after disconnect, Apple's sample order, no disconnect() at all, GKMatchmaker.cancel() afterwards). The gcksession.recvproc / sendproc thread pair stays. So there is no application-side retain of the match to look for. WHAT IS UNDER A GKMATCH ON iOS 27 Read by reflection on the device (class_copyIvarList on the live objects), because the macOS layout is different: GKMatch._transport = GKCompositeTransport ._viceroyTransport = GKViceroyTransport ._connection = GKConnectionInternal (owns the C session and the CDXClient) .cdxClient = CDXClient -> .delegate = GKConnectionInternal ._eventDelegate = GKSessionInternal ._session = GKViceroySession -> ._session = GKSessionInternal ._relay = GKViceroyRelay ._fastSyncTransport = FastSyncTransport (new, Swift) WHAT SURVIVES, AND WHAT DOES NOT HELP After disconnect(), sending disconnectFromAllPeers to the GKSessionInternal, stopHolePunchTimer / stopListeningOnSockets / invalidate to the CDXClient, preRelease to the GKConnectionInternal, then nil'ing every back-reference between them (session -> delegate/privateDelegate/dataReceiveHandler/connection, connection -> eventDelegate/cdxClient, cdxClient -> delegate_, transport -> session/connection/relay), cancelling the remaining dispatch sources and setting _stopHandlingEvents / _shutdown: GKViceroyTransport: released GKConnectionInternal: ALIVE, retain count stable at 4 (+1 for the reading) CDXClient: ALIVE, retain count stable at 4 GKSessionInternal: ALIVE, retain count stable at 3 recvproc/sendproc pair: still running Those owners are not ivars and not dispatch sources. They sit across the C boundary: the GCKSession holds its Objective-C contexts, and it would only be destroyed in their dealloc. GameKitServices exports 51 symbols and no GCKSession* function, so there is nothing to call. THE NETWORK SIDE IS NOT THE CHANNEL EITHER GameKit does close the finished session's own sockets (:16402) at disconnect(). The one UDP socket it leaves open is the relay client's — one unconnected socket on an ephemeral port, through which the leaked CDXClient keeps punching its hole every 30 s. Replacing that descriptor in place with a UDP socket connected to the discard port (dup2, so the fd number stays taken) 15 s before the next search: match forms normally, and crashes identically. (Do not close() it: the leaked client keeps sending on that fd number every 30 s, onto whatever socket gets it next — and a sweep that is not snapshotted at teardown time will close the next search's own relay socket, which then never connects.) THE TRIGGER IS THE C-LEVEL ICE RETRY, ON A FIXED CLOCK The crash lands 14–21 s after the second match starts exchanging data, never earlier — and a second match that is quit before that never crashes (four in a row, no crash). In the unified log the sequence is: bind -> 0.3 s later "packet-from-unknown-session" on the new CDXClient -> "ICEStopConnectivityCheck() found no ICE check with call id" -> connected anyway -> ~14 s -> tellDelegate_didReceiveBand_RetryICE -> CFRetain(1). Switching off the transport health monitor on both peers at connection (stopMonitoringAll, GKTransportContext.healthMonitorEnabled = NO, _healthMonitor nil'd — all confirmed to land) changes nothing, so the retry is not the monitor's; it comes from gckSessionCheckPendingConnections itself (iDDsExpected=1 is logged unsatisfied both times). WHERE THAT LEAVES AN APP One real-time match per process on iOS 27, detected at runtime by counting gcksession.recvproc threads (task_threads + pthread_getname_np) rather than by OS version, so it stops firing the day the leak is fixed. Everything above is in FB24789094. If anyone from GameKit reads this: the leak is visible in any app that plays two real-time matches in one launch, and the crash needs the second one to live past its first ICE retry. Happy to run anything you want on these devices.
Topic: Graphics & Games SubTopic: GameKit Tags:
Replies
Boosts
Views
Activity
2d
Reply to iOS 18.4 - HomeKit actions from AppIntent fail when triggered from Widget
I’ve finally resolved this issue after many hours of debugging — posting the full solution here in case it helps others. ✅ Problem Since iOS 18.4, calling HomeKit APIs (like toggling accessories) from an AppIntent triggered by a Widget fails with the following error: Error Domain=HMErrorDomain Code=80 "Missing entitlement for API." UserInfo={ NSLocalizedFailureReason=Handler does not support background access, NSLocalizedDescription=Missing entitlement for API. } This happens only when the intent runs inside the widget process, not when it runs in the main app (even in background). ✅ Solution Part 1: Force AppIntent to run in main app process To bypass the limitations of the widget process, I made my AppIntent run in the main app instead, using the ForegroundContinuableIntent protocol. You can do this by adding the following extension: @available(iOSApplicationExtension, unavailable) extension MyActionIntent: ForegroundContinuableIntent {} Then declare your AppIntent as usual: struct MyActionIntent: AppIntent { init() {} static var openAppWhenRun: Bool { return false // Keep this false to avoid full app UI presentation } func perform() async throws -> some IntentResult { // Call HomeKit APIs here return .result() } } With this, even when triggered from a widget, the intent runs in the app's process — which has proper entitlements and access to HomeKit. 🧨 BUT... another hidden problem was causing crashes After applying the above fix, the intent still didn't seem to work — or worse, the app was crashing silently when launched in background. After deeper investigation, I found the real cause: I had a SwiftUI .backgroundTask(.appRefresh("MyBGTaskID")) { ... } modifier declared on the WindowGroup. Apparently, when the app is launched in background by an AppIntent, this SwiftUI modifier behaves incorrectly — the background task is not properly registered, and causes a crash when triggered. But this crash is invisible if you test by launching the app manually — because in that case, everything works fine, and the .backgroundTask behaves normally. ✅ Solution Part 2: Register background task manually I fixed this issue by removing the SwiftUI .backgroundTask modifier and manually registering the background task the "classic" way, in the init() of the @main app struct: import BackgroundTasks @main struct MyApp: App { init() { BGTaskScheduler.shared.register(forTaskWithIdentifier: "MyBGTaskID", using: nil) { task in // Handle your task here } } var body: some Scene { WindowGroup { ContentView() } } } ✅ Summary iOS 18.4 introduced stricter sandboxing for AppIntents running inside Widgets. Use ForegroundContinuableIntent to force your AppIntent to run in the main app context (where HomeKit works). Beware of SwiftUI .backgroundTask modifiers — they may cause background crashes when the app is launched by an AppIntent. Use manual registration via BGTaskScheduler.shared.register(...) instead. Let me know if anyone else experienced the same issue, or if you found a better way to debug background crashes in SwiftUI contexts. Hope this helps! 🙌
Replies
Boosts
Views
Activity
Apr ’25
Reply to Xcode 15.3 & iOS 17.4 app install issue: Framework is missing its bundle executable.
I find the reason in my case at least. I expect it will help others too. I don't know why but the build setting "Skip App Store Deployment" was enabled for DEBUG configuration... Changing it to "NO" fixed the issue. Now I don't know if it should be considered as an issue/bug or not. Clement
Replies
Boosts
Views
Activity
Mar ’24
Reply to iOS + WatchOS Build: How to automatize?
Answering myself :D I forgot to add Watch App as a Target Dependency: Project > Build Phase > Project Dependency https://stackoverflow.com/questions/37449354/error-no-such-file-or-directory-while-archiving-ios-and-watchos-app
Replies
Boosts
Views
Activity
Sep ’23
Reply to Widgets: Detect StandBy night mode iOS 17
OK! I have found solution by myself using the showsWidgetContainerBackground Environment Value. I don't detect directly the StandBy mode but I detect that the WidgetContainerBackground has been removed. In widgetRenderingMode fullColor that means its the StandBy mode. At least it's true currently in iOS 17.0 @Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground @Environment(\.widgetRenderingMode) var widgetRenderingMode ... ZStack { // If ContainerBackground will be removed, show the light background if (!showsWidgetContainerBackground && widgetRenderingMode == .fullColor) { Color.white.opacity(0.1).cornerRadius(cornerRadius) } WidgetContentView() .containerBackground(for: .widget) { backgroundView(viewSize: panelSize) } }
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Aug ’23
Reply to How to prevent ios17 interactive widgets to open the app after an interaction?
It seems to occurs less often with iOS 17 beta 5 but it still happens :(
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Aug ’23
Reply to How in interactive widgets in ios 17 to prevent the opening of the application by clicking on the widget?
I have still exactly the same behavior on iOS 17 beta 4. It is absolutely unpredictable when the tap on an interactive item (button or toggle) will pass through and will open the app. I did put a full size interactive background button (with an intent) doing nothing to try to catch missed click. It improve behavior but some tap still open the app with no reason. It looks like a bug but I am afraid it will persist for a while... :(
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Aug ’23
Reply to How to prevent ios17 interactive widgets to open the app after an interaction?
Hi! I have still exactly the same behavior on iOS 17 beta 4. It is absolutely unpredictable when the tap on an interactive item (button or toggle) will pass through and will open the app. I did put a background interactive button (with an intent) doing nothing to try to catch miss click. It improve behavior but some tap still open the app with no reason. It looks like a bug but I am afraid it will persist for a while... :(
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Aug ’23
Reply to How in interactive widgets in ios 17 to prevent the opening of the application by clicking on the widget?
What about putting a big button calling a AppIntent that do nothing as background? I didn't try to put an overlay a button on another button but if it works it may be your solution. Otherwise you'll have to put some inactive buttons around your active button I think.
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Jun ’23
Reply to What does WIDGET_BACKGROUND_API_ADOPTION_PROMPT mean?
So same issue here. I missed a log message in the console: The widget background view is missing. Please ensure that you have called the `containerBackground(for: .widget) {…}` modifier in your widget view. Just add the new .containerBackground(for:) in your widget view and it will resolve the issue. https://developer.apple.com/videos/play/wwdc2023/10027?time=180
Replies
Boosts
Views
Activity
Jun ’23
Reply to What does WIDGET_BACKGROUND_API_ADOPTION_PROMPT mean?
It seems to be related to our projets. I tried the Emoji Rangers Apple sample code and there is not this warning on the widgets.
Replies
Boosts
Views
Activity
Jun ’23
Reply to What does WIDGET_BACKGROUND_API_ADOPTION_PROMPT mean?
Same issue here. I have this warning even in the Widget Library Preview when adding a new Widget. I suppose there is something (like a prompt?) is missing in the beta 1 but can't see any related issue in the release notes.
Replies
Boosts
Views
Activity
Jun ’23
Reply to iPhone 14 Pro (and 14 Pro Max) Native Screen Size
Thanks to geoffhackworth (https://twitter.com/geoffhackworth) it seems that Xcode-14 TestFlight builds are treated as Xcode 13 builds and are scaled to the 12/13 Pro layout. So the issue will only occurs for TestFlight build. Thank you geoffhackworth (https://twitter.com/geoffhackworth) More about this here: https://twitter.com/geoffhackworth/status/1573652281848905728
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to iPhone 14 Pro (and 14 Pro Max) Native Screen Size
Perhaps only on some specific conditions? Zoomed display seems to produce a 320 x 693 screen size. Perhaps there is another setting that can make it switch to 390x844.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to Running app built in Xcode 14 on iOS 15 results in missing WidgetKit symbol crash
Since Xcode 14.0 beta 4, I have have a different error but still facing a black Widget on iOS 15.x
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’22