Post

Replies

Boosts

Views

Activity

Reply to VoIP PKPushKit notifications not delivered when powerd assertion policy 3 hits before apsd completes APNs reconnection
Based on our analysis of the TCP traffic betwen the iPhone and APNs when the device is locked, we found that the TCP connection can remain idle for up to 10 minutes. We also discovered that the carrier CGNAT employ a 5 minute idle timeout on TCP connection, therefore the iPhone will be in a blackout for up to 5 minutes. As seen in the packet capture screenshot below. The last packet received from the APNs server was at 13:41:37. The iPhone sent a packet at 13:51:12 and kept retransmitting until 13:51:59 for more than 1 minute. A new TCP connection established at 13:52:12. It would be helpful if you can confirm the max timeout/keep-alive for APNs TCP connection as reference for Telecom provider.
Topic: App & System Services SubTopic: General Tags:
Jun ’26
Reply to VoIP PKPushKit notifications not delivered when powerd assertion policy 3 hits before apsd completes APNs reconnection
Thank you — this is very helpful, especially the clarification that PKPushRegistry plays no role in delivery and that the new mustReport delegate is the recommended direction. We will adopt that delegate and post a "Call Missed" notification when delivery latency is too high. Before we close this out, there is one point we'd like your read on, because it's the main reason we escalated. This is a recent regression, not a long-standing condition. These same users, on the same devices, same carriers, and the same usage pattern, received VoIP calls reliably until approximately mid-May 2026 (about a month ago). The onset was relatively sudden and is now consistently reproducible. Nothing changed on our side in that window — same app build, same push server, same apns-expiration — yet reliability dropped sharply across multiple users at roughly the same time. It is predominantly a cellular problem, but it is not exclusive to cellular — we have also reproduced it on Wi-Fi, just far more rarely and with much greater difficulty. Combined with the fact that the failure is cross-app (WhatsApp's own VoIP push was delivered ~3 minutes late on the same device in our tests), our working assumption is that something changed at the platform or network layer recently, rather than our implementation degrading. Question: Were there changes in a recent OS release (or in APNs reconnection / power-management behavior) around that timeframe that could increase how long apsd stays unable to re-establish the APNs connection before the device sleeps? We're trying to understand whether this is expected new behavior or a regression worth a bug report. For completeness, confirming our current implementation matches your guidance: apns-expiration = 0 — every VoIP push is sent with apns-expiration = 0 (immediate-or-discard), specifically to avoid the long-delayed expired-push deliveries you described. We report the call synchronously inside the push handler. The PKPushRegistry is created once and held strongly for the controller's lifetime (not a local var), and we call reportNewIncomingCall(with:update:completion:) synchronously within pushRegistry(_:didReceiveIncomingPushWith:for:completion:) before invoking the PushKit completion handler: final class PushController: NSObject, PKPushRegistryDelegate { // Held strongly for the controller's lifetime — not a local var. private var voipRegistry: PKPushRegistry? func enablePushKit() { let registry = PKPushRegistry(queue: .main) registry.delegate = self registry.desiredPushTypes = [.voIP] self.voipRegistry = registry // retained } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { let uuid = UUID() let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .generic, value: payload.dictionaryPayload["caller"] as? String ?? "") update.hasVideo = (payload.dictionaryPayload["callType"] as? String) == "video" // Reported synchronously, in the same run-loop turn as the push; // the PushKit completion handler is only called afterwards. provider.reportNewIncomingCall(with: uuid, update: update) { error in completion() } } } The CXProvider is created eagerly at app launch (before PushKit registration) so it is never nil when a push arrives. Evidence attached — same device and build: Cellular (frequent): apsd repeatedly logs Connection closed WWAN with isWWANUsable YES, isWiFiUsable NO (no Wi-Fi to fail over to), and no VoIP push is delivered within the call window. Cross-app (cellular): WhatsApp's own VoIP push (net.whatsapp.WhatsApp) was delivered ~3 min 22 s and ~3 min 34 s late in two separate tests on the same device. Wi-Fi (typical): APNs delivers the push and the call is reported in ~77 ms (apsd … Received message for enabled topic … → app launched → reportNewIncomingCallWithUUID). This is the common Wi-Fi behavior; however we have also observed the same failure on Wi-Fi on rare occasions, which is why we don't believe it is purely a cellular-radio condition. FAIL_17-48_cellular-idle_all-apps-comera-whatsapp-teams.txt FAIL_13-43_cellular_whatsapp-late-3m34s.txt FAIL_13-08_cellular_push-never-delivered.txt Our open question is specifically why this became common only recently, given nothing changed in our app or push pipeline.
Topic: App & System Services SubTopic: General Tags:
Jun ’26
Reply to VoIP PKPushKit notifications not delivered when powerd assertion policy 3 hits before apsd completes APNs reconnection
I have filed a bug report with incident number: FB23374513
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jun ’26
Reply to VoIP PKPushKit notifications not delivered when powerd assertion policy 3 hits before apsd completes APNs reconnection
Based on our analysis of the TCP traffic betwen the iPhone and APNs when the device is locked, we found that the TCP connection can remain idle for up to 10 minutes. We also discovered that the carrier CGNAT employ a 5 minute idle timeout on TCP connection, therefore the iPhone will be in a blackout for up to 5 minutes. As seen in the packet capture screenshot below. The last packet received from the APNs server was at 13:41:37. The iPhone sent a packet at 13:51:12 and kept retransmitting until 13:51:59 for more than 1 minute. A new TCP connection established at 13:52:12. It would be helpful if you can confirm the max timeout/keep-alive for APNs TCP connection as reference for Telecom provider.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jun ’26
Reply to VoIP PKPushKit notifications not delivered when powerd assertion policy 3 hits before apsd completes APNs reconnection
Thank you — this is very helpful, especially the clarification that PKPushRegistry plays no role in delivery and that the new mustReport delegate is the recommended direction. We will adopt that delegate and post a "Call Missed" notification when delivery latency is too high. Before we close this out, there is one point we'd like your read on, because it's the main reason we escalated. This is a recent regression, not a long-standing condition. These same users, on the same devices, same carriers, and the same usage pattern, received VoIP calls reliably until approximately mid-May 2026 (about a month ago). The onset was relatively sudden and is now consistently reproducible. Nothing changed on our side in that window — same app build, same push server, same apns-expiration — yet reliability dropped sharply across multiple users at roughly the same time. It is predominantly a cellular problem, but it is not exclusive to cellular — we have also reproduced it on Wi-Fi, just far more rarely and with much greater difficulty. Combined with the fact that the failure is cross-app (WhatsApp's own VoIP push was delivered ~3 minutes late on the same device in our tests), our working assumption is that something changed at the platform or network layer recently, rather than our implementation degrading. Question: Were there changes in a recent OS release (or in APNs reconnection / power-management behavior) around that timeframe that could increase how long apsd stays unable to re-establish the APNs connection before the device sleeps? We're trying to understand whether this is expected new behavior or a regression worth a bug report. For completeness, confirming our current implementation matches your guidance: apns-expiration = 0 — every VoIP push is sent with apns-expiration = 0 (immediate-or-discard), specifically to avoid the long-delayed expired-push deliveries you described. We report the call synchronously inside the push handler. The PKPushRegistry is created once and held strongly for the controller's lifetime (not a local var), and we call reportNewIncomingCall(with:update:completion:) synchronously within pushRegistry(_:didReceiveIncomingPushWith:for:completion:) before invoking the PushKit completion handler: final class PushController: NSObject, PKPushRegistryDelegate { // Held strongly for the controller's lifetime — not a local var. private var voipRegistry: PKPushRegistry? func enablePushKit() { let registry = PKPushRegistry(queue: .main) registry.delegate = self registry.desiredPushTypes = [.voIP] self.voipRegistry = registry // retained } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { let uuid = UUID() let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .generic, value: payload.dictionaryPayload["caller"] as? String ?? "") update.hasVideo = (payload.dictionaryPayload["callType"] as? String) == "video" // Reported synchronously, in the same run-loop turn as the push; // the PushKit completion handler is only called afterwards. provider.reportNewIncomingCall(with: uuid, update: update) { error in completion() } } } The CXProvider is created eagerly at app launch (before PushKit registration) so it is never nil when a push arrives. Evidence attached — same device and build: Cellular (frequent): apsd repeatedly logs Connection closed WWAN with isWWANUsable YES, isWiFiUsable NO (no Wi-Fi to fail over to), and no VoIP push is delivered within the call window. Cross-app (cellular): WhatsApp's own VoIP push (net.whatsapp.WhatsApp) was delivered ~3 min 22 s and ~3 min 34 s late in two separate tests on the same device. Wi-Fi (typical): APNs delivers the push and the call is reported in ~77 ms (apsd … Received message for enabled topic … → app launched → reportNewIncomingCallWithUUID). This is the common Wi-Fi behavior; however we have also observed the same failure on Wi-Fi on rare occasions, which is why we don't believe it is purely a cellular-radio condition. FAIL_17-48_cellular-idle_all-apps-comera-whatsapp-teams.txt FAIL_13-43_cellular_whatsapp-late-3m34s.txt FAIL_13-08_cellular_push-never-delivered.txt Our open question is specifically why this became common only recently, given nothing changed in our app or push pipeline.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jun ’26