pushtotalk pushes accepted by APNs (200) are not delivered for several minutes after a delivered push

Environment: iPhone 17 Pro, iOS 27.0, Xcode 27, dev build (aps-environment development), sandbox APNs, token-based auth.

The app uses the PushToTalk framework with one restored channel; audio is WebRTC, started only after didActivate. Push headers: apns-push-type pushtotalk, apns-topic <bundle id>.voip-ptt, apns-priority 10, apns-expiration 0. Payload about 460 bytes. APNs returns 200 to every push in about 250 ms.

What we then see is after a pushtotalk push is delivered and handled, the next push sent about 6 to 7 minutes later is not delivered to the app (no incomingPushResult call), although APNs returned 200. Pushes sent about 13 or more minutes after the last delivered one are almost always delivered. Overnight automated runs, phone on power, Focus off, no calls. Pushes sent after a delivered push: 38 of 38 lost (one run), 31 of 32 lost (another run). Pushes sent about 13+ minutes after the last delivered push: 38 of 40 delivered, and 37 of 41 in the other run. Lost pushes are not late: none arrived within 5 minutes after sending.

What we ruled out:

  1. App state: the loss is the same whether the woken app is terminated about 37 s after the push or left to suspend on its own, and whether or not it sets activeRemoteParticipant to nil when the remote audio ends (the audio session deactivates in that case).
  2. Push token: the server's token matches the token the app last received.
  3. Focus and calls: Focus off, and pushes near calls were excluded.

Separately, pushes sent within the first few minutes after the app is launched (by hand or by devicectl) are also mostly lost.

Questions:

  1. Is there a limit, documented or expected, on how often the system delivers pushtotalk pushes or wakes the app after a recent incoming push?
  2. Could apns-expiration 0 cause these pushes to be discarded, for example if the device is briefly unreachable after a Push to Talk wake? Is a short non-zero expiration appropriate for pushtotalk?
  3. Is this expected in the sandbox environment, and would production behave differently?
  4. Beyond setting activeRemoteParticipant to nil when the remote speaker stops, should the app do anything after handling an incoming push so that the next push is delivered? We can share log excerpts or a sysdiagnose on request.

So, the "delayed push" issue you're describing is a longstanding behavior of APNS and is basically "always" caused by your device not being connected to the APNS server at the time the push was sent to the device. At a technical level, what's actually happening is that the push server queues your push for delivery and that push is then delivered at some later point when the device reconnects.

FYI, the new CallKit delegate described here was SPECIFICALLY created to address this issue. There's no PTT equivalent to that API because PTT apps are able to discard/ignore pushes in a way CallKit apps cannot.

  1. Is there a limit, documented or expected, on how often the system delivers pushtotalk pushes or wakes the app after a recent incoming push?

This isn't an app or system level issue.

  1. Could apns-expiration 0 cause these pushes to be discarded, for example if the device is briefly unreachable after a Push to Talk wake? Is a short non-zero expiration appropriate for pushtotalk?

We've long recommended expiration "0" because any non-zero value will significantly increase the frequency of long-delayed pushes.

  1. Is this expected in the sandbox environment, and would production behave differently?

The issue will occur in production as well, but, yes, it does tend to be much worse in the sandbox environment. I'm not sure of exactly what causes it, but, from experience, the device tends to be slower at bringing the sandbox connection up and quicker to tear it down, both of which exacerbate this issue.

One other thing to be aware of here is that network issues (typically on Wi-Fi) can DIRECTLY create these failures in ways that are not at all obvious.

  1. Beyond setting activeRemoteParticipant to nil when the remote speaker stops, should the app do anything after handling an incoming push so that the next push is delivered?

No. The device has a fairly limited role in the process, and your app has none at all.

We can share log excerpts or a sysdiagnose on request.

SO, I'm going to decline that opportunity, but I want to explain why. Over the years, I've gone through MANY, MANY logs "investigating" these dropped/delayed pushes. Across all of those investigations, an OVERWHELMING majority have been caused by these two issues:

  1. The push actually worked fine, but the app failed, typically by crashing at launch or otherwise failing to initialize properly. Here is an example.

  2. The device did not have a working connection to our push servers at the time the push was sent. As soon as it did have a working connection, it connected to the server and then immediately delivered the push. Here is an example.

Note that #2 then breaks into two categories:

  1. The device didn't have any working network connection.

  2. The device APPEARED to have a working Wi-Fi connection, but the connection to APNS wasn't actually functioning correctly due to network-level issues not visible to the device.

The key point here is that you're starting with the assumption that "the system" (meaning the code running on the device) is the most likely failure point. It isn't. The points that actually fail here are your app and the network.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

pushtotalk pushes accepted by APNs (200) are not delivered for several minutes after a delivered push
 
 
Q