The APNs delay to send notification on iOS 26.4

In my VoIP app, we use StartRing and StopRing via VoIP push to my app.

But recently, I found some disordered VoIP notifications, my VoIP app received the StopRing push before the StartRing push.

Examples:

Server log:

// send StartRing
startring: -  Apr 9, 2026 @ 14:54:43.255
.."pushType":"voip","priority":10, ...

// send StopRing
stop-ring Apr 9, 2026 @ 14:54:47.645
..."pushType":"background","priority":5,"...

VoIP app log:

// receive StopRing
2026-04-0909:54:48.858 CDT : INFO : [RcRtc] [0x1feeba1c0] [PushNotificationParser]call push notification handled. action: StopRing telephony session id: s-a0dd8601926c7z19d72bbf8b9z1e62ec10000 sid: 178503189447188

// receive StartRing
2026-04-0909:54:49.524 CDT : INFO : [RcRtc] [0x1feeba1c0] [PushNotificationParser]call push notification handled. action: StartRing telephony session id: s-a0dd8601926c7z19d72bbf8b9z1e62ec10000 sid: 178503189447188

Then we can see the StartRing send first, but received in the app after the StopRing. The StartRing took abunt 6s to send and the StopRing took about 1s.

So I guess there is an issue in the APNs part on iOS26.4. We saw there is a peak after iOS26.4 and iOS 26.4.1 than old iOS versions.

Thanks.

While it is unlikely that this has anything to do with iOS version, we can try tracing the notifications to see if this is a coincidental connection problem, if you supply the following info:

  • the apns-id of the delayed notification
  • the time it was sent (with time zone)
  • the time it was received

If you believe this is definitely a bug in iOS 26.4 and want the notification team to look into it, you can instead file a bug report and in there also include in addition to the above info:

  • apns-topic
  • app bundle-id
  • any logging you have from your app, your push server, etc.
  • the push token you sent the delayed push to

Here are detailed info.

# server log:
#stop-ring
"@timestamp": ["2026-04-09T14:54:47.704Z"], 
"apns_topic":"com.glip.mobile"
"device_token":"86693487CCF6217018D112FFE7898A6C6C52115116B89FE254FCEC43A399647E"
"apns_id":"40779e9b-8878-4861-9dcb-86f31fb66f1e"
"status_code":"success"


#start-ring
"@timestamp": ["2026-04-09T14:54:43.315Z"],
"apns_topic":"com.glip.mobile.voip"
"device_token":"44EB6B069D877957908626E4978B32F798344DDEAD03961E4A8EFA0BBE9FB2EE"
"apns_id":"7c4e863a-5aab-44cb-8739-2e3868fc7560"
"status_code":"success"


# clent app log (CDT time)
#receive stop ring 
2026-04-0909:54:48.858 CDT : INFO : [RcRtc] [0x1feeba1c0] [PushNotificationParser]call push notification handled. action: StopRing telephony session id: s-a0dd8601926c7z19d72bbf8b9z1e62ec10000 sid: 178503189447188

# receive start ring.
2026-04-0909:54:49.524 CDT : INFO : [RcRtc] [0x1feeba1c0] [PushNotificationParser]call push notification handled. action: StartRing telephony session id: s-a0dd8601926c7z19d72bbf8b9z1e62ec10000 sid: 178503189447188

btw, I found a similar thread here, maybe related?

https://developer.apple.com/forums/thread/820550

iCloud Sync not working with iPhone, works fine for Mac.

Feedback id: FB22528150

Any update? Apple dev?

Knock knock?

But recently, I found some disordered VoIP notifications. My VoIP app received the StopRing push before the StartRing push.

Do you know what was happening on the device? It's possible there is a push level issue involved here, but I can also see why this could happen under very "normal" conditions.

Notice the odd discrepancy in timing:

Then we can see the StartRing send first, but received in the app after the StopRing. The StartRing took about 6s to send and the StopRing took about 1s.

The pushes were sent 5s apart.

// receive StopRing
2026-04-0909:54:48.858

// receive StartRing
2026-04-0909:54:49.524

...but were delivered ~2/3 of a second from each other. You are actually thinking about the question here the wrong way— the question isn't just "why did stop arrive before start", it's "how did they end up arriving so close to each other".

I suspect what started this is that the device was actually offline at the point the original push was sent, then came back online shortly after the stop push was queued. So, the starting point here is that both pushes reach the device at roughly the same time, when the device came back online.

At that point, a few different factors come into play.

To start with, APNS priority is really about overall "management" at the network level, not absolute priority at the individual push level. That is, if you submit a VoIP push and a standard push "at the same time", which one will ACTUALLY reach the device first isn't formally defined. They're both moving through the APNS infrastructure and trying to micromanage push ordering would be both expensive (in CPU time) and probably end up slowing everything down for no real benefit.

Similarly, when pushes are queued, we don't necessarily try and sort the queue pushes to ensure they're in the "right" order. I don't actually know what order we deliver the push back log, but there's a decent chance we intentionally deliver newer pushes "first", under the theory that it's more important that recent pushes get processed vs. older.

Next, there's going to be some kind of variation between standard push delivery and VoIP push delivery— they're both moving through separate daemon's, so they aren't going to have exactly the same performance.

That leads to the final and likely most important factor, which is what actually happened within your app. In particular:

  1. Was your app running when the pushes arrived?

  2. Where EXACTLY did you receive the push notification, and when do you initialize PKPushRegistry?

Those points are critical because it's fairly easy to unintentionally create EXACTLY the kind of time gap you're seeing. All you need to do is:

a) Use an "early" delegate like application(_:didFinishLaunchingWithOptions:) or application(_:didReceiveRemoteNotification:) to receive your push.

b) Set up PKPushRegistry object relatively "late", for example, as part of your early interface bring-up.

A configuration like that then sets up the following situation:

  • Both pushes arrive and are processed,

  • The APNS notification is queued for delivery but the app NOT woken or launched.

  • callservicesd receives the VoIP push and launches your app.

  • Your app launches and receives the APNS push in an early delegate.

  • Your app continues initializing (for 2/3 of a second?).

  • Your app creates its PKPushRegistry and receives the VoIP push.

Which brings me back to my first question... what was happening on the device?

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

The log is from our server log, no clue about the user devices.

I can understand your explanation. So two questions here.

  1. Why and when will a device be offline? How to avoid it?
  2. We saw a peak of "disorderred notification" on the iOS 26.4+. I don't know if there is a change or an issue here.

btw, I posted the apns-id above, are they helpful?

The log is from our server log, no clue about the user devices.

OK. So the critical point to understand is that issues like this CAN'T actually be investigated using only server or app log data. The problem here is that virtually any network-level issue always has two explanations:

a). Something went wrong in the app/system.

b). Something happened to the physical device that made the resulting behavior inevitable.

The only way to separate those two cases is to have some amount of information about what the device was actually "doing". Even worse, trying to investigate WITHOUT being able to separate those two cases is often far less useful than you might think. The problem here is that, even if/when there is a real issue, the second case (b) is almost always present, which ends up masking the evidence that would otherwise be useful.

I'll also note that my entire explanation is ENTIRELY speculative. As another possibility, it's also possible that callservicesd is/was crashed and that the delayed VoIP push was simply a side effect of its relaunch. It's also possible that changes in our frameworks are blocking your PushKit thread in a way that previous releases happened to not block it.

That's two more possibilities off the top of my head, but the key point is that there isn't any way to know or investigate more deeply without actual data about/from the device itself. Without that information, all you can really do is speculate.

Case in point:

Why and when will a device be offline?

I have no idea. You’re asking this question with the assumption that the system had some involvement with the process, when the actual issue could be no more complicated than the user losing connectivity when they got on the subway.

How to avoid it?

Same answer, as above.

We saw a peak of “disordered notification" on the iOS 26.4+. I don't know if there is a change or an issue here.

OK. Out of curiosity, how closely have you compared your earlier behavior to the current behavior? In particular:

  • Is the rate of "paired notifications" (meaning, your app received both notifications for a given call) the same or different?

If the rate has changed, then this might simply be a case of notifications reaching the device that were previously discarded.

  • On previous versions, what was the time gap between the two pushes IF the VoIP push was delayed by a substantial amount?

As I alluded to above, under the right circumstances, there's an inherent race condition between the delivery of standard pushes and VoIP pushes. It's possible changes to the system have simply "flipped" that race, not that anything has fundamentally changed.

Finally, and perhaps most importantly, why do you care about this?

Ultimately, you were ALWAYS going to do one of two things with this call:

  1. Report the call and then end it.

  2. Not report the call at all (using the new delegate we just introduced to support this)*.

In both cases, getting the silent push "first" should have actually IMPROVED your app, not hurt it, since you now have earlier information about what you're going to do with the call.

*You have adopted the new delegate, right?

BTW, I posted the apns-id above, are they helpful?

In my experience, no, not really. Looking at this from the APNs server side can be helpful if you're trying to investigate a specific issue that you've already tied to some other external factor. For example, a few teams have found it helpful as a way to confirm local NAT failures. They were already investigating a particular location and device set where pushes were failing in a systemic way and they'd found through sysdiagnose data that the device itself "thought" it had a working push connection. Our server logs showed that connection was NOT functional, which led back to the underlying cause, which was a poor NAT implementation which was breaking the connection and notifying the server but NOT notifying the client.

However, that's the exception, not the rule. Blindly checking individual push failures generally only tells you exactly what you already knew or suspected— namely that the push left our server shortly before it reached the device and that it was delivered as "soon" as it could have been.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

The APNs delay to send notification on iOS 26.4
 
 
Q