pushkit and callkit

I am currently implementing VoIP push notifications in my iOS app using PushKit. On iOS 18, I am able to receive VoIP notifications successfully when the app is in the foreground. However, when the app is in the background or in a terminated (kill) state, the notifications do not arrive.

In earlier iOS versions, my existing implementation worked as expected across all app states. This issue seems to have started after testing on iOS 18, which appears to have introduced stricter permission or background execution requirements.

Questions:

  1. Has iOS 18 introduced new permission requirements or entitlements for VoIP push notifications?

  2. Do I need to explicitly request a new type of user permission for VoIP notifications?

  3. Are there additional background modes, Info.plist keys, or PushKit changes required for VoIP to work in background and terminated states on iOS 18?

Additional Information:

. Foreground: Works fine, pushRegistry(_:didReceiveIncomingPushWith:for:completion:) is triggered.

. Background/Terminated: No call to the above delegate method.

. Using correct voip push type in the payload.

. PushKit is configured in AppDelegate.

. Background modes for "Voice over IP" and "Background Processing" are enabled.

. Using a real device with iOS 18 for testing (not simulator).

Any guidance or updated documentation references for handling VoIP pushes in iOS 18 would be greatly appreciated.

Answered by DTS Engineer in 853389022
  1. Has iOS 18 introduced new permission requirements or entitlements for VoIP push notifications?

No. The last significant change here was the iOS 13 CallKit requirements. There hasn't been any change to them since then.

Do I need to explicitly request a new type of user permission for VoIP notifications?

No.

Are there additional background modes, Info.plist keys, or PushKit changes required for VoIP to work in background and terminated states on iOS 18?

No.

Looking over your list, I did notice this:

. Background modes for "Voice over IP" and "Background Processing" are enabled.

Did you also include "audio"/"Audio, AirPlay, and Picture in Picture"?

Historically, the architecture of VoIP apps has always relied on two different background categories in order to function:

  1. "voip” -> Allows apps to use PushKit for call notifications and CallKit for call management.

  2. "audio” -> Keeps the app awake in the background while the app is actually on a call (the same way it would keep any long-playing audio app awake).

That's the "conceptual" architecture VoIP apps are designed to be built. However, the reality is that the audio system is "aware" of the VoIP category as well (notably, it also uses this to restrict access to the phone audio session) and much of CallKit's audio session management actually goes directly through callservicesd, not from that app itself. That means that it's often been the case that VoIP apps CAN function with "audio", even though the architecture above means that they should NOT be able to function.

The results of all this is that IF a VoIP app leaves off the audio background category exactly what generally happens is:

  • The CallKit and the app still "work" in the basic sense.

  • "Something" won't work properly.

...with the specifics depending entirely on the specific iOS version. However, it's important to understand that the real bug here is that CallKit works at all, NOT whatever breaks.

Any guidance or updated documentation references for handling VoIP pushes in iOS 18 would be greatly appreciated.

The next step here is to reproduce the problem on a test device, then trigger and collect a sysdiagnose, open the system log archive, and then dig into the log to "see what happened". callservicesd has good logging diagnostics, so it's not difficult to trace a VoIP push from its arrival in APNSD all the way to its full processing by callservicesd. I've done this kind of analysis on a few different forum threads, see here, here, and here for examples.

A few notes on that process:

  • If this has been happening for a while, then it's very likely that callservicesd has stopped delivering pushes to your app due to reporting failures. Delete and reinstall the app to reset that.

  • The Phone (General) debug profile will provide more detailed logging from callservicesd. It's not necessary to track basic push handling, but it can be helpful, particularly for more complicated issues.

Focussing on the log analysis process:

  • A sysdiagnose log archive contains hours and even days of data, so it's not necessary to be exact about when you trigger the log.

  • Rebooting the device purges significant log data, so don't reboot until you've collected the data.

  • It's easy to overlook the "Showing" button in the bottom left of Console.app; it controls the time frame you're looking at.

  • Right-clicking on any log field will give you options for including/excluding data based on the field content, and you can also edit the entry that creates in the top right "search" field. This makes it easy to quickly narrow down to what you're actually interested in.

Hopefully, that's enough to get you started. Please let me know what you find or if you have any questions.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

  1. Has iOS 18 introduced new permission requirements or entitlements for VoIP push notifications?

No. The last significant change here was the iOS 13 CallKit requirements. There hasn't been any change to them since then.

Do I need to explicitly request a new type of user permission for VoIP notifications?

No.

Are there additional background modes, Info.plist keys, or PushKit changes required for VoIP to work in background and terminated states on iOS 18?

No.

Looking over your list, I did notice this:

. Background modes for "Voice over IP" and "Background Processing" are enabled.

Did you also include "audio"/"Audio, AirPlay, and Picture in Picture"?

Historically, the architecture of VoIP apps has always relied on two different background categories in order to function:

  1. "voip” -> Allows apps to use PushKit for call notifications and CallKit for call management.

  2. "audio” -> Keeps the app awake in the background while the app is actually on a call (the same way it would keep any long-playing audio app awake).

That's the "conceptual" architecture VoIP apps are designed to be built. However, the reality is that the audio system is "aware" of the VoIP category as well (notably, it also uses this to restrict access to the phone audio session) and much of CallKit's audio session management actually goes directly through callservicesd, not from that app itself. That means that it's often been the case that VoIP apps CAN function with "audio", even though the architecture above means that they should NOT be able to function.

The results of all this is that IF a VoIP app leaves off the audio background category exactly what generally happens is:

  • The CallKit and the app still "work" in the basic sense.

  • "Something" won't work properly.

...with the specifics depending entirely on the specific iOS version. However, it's important to understand that the real bug here is that CallKit works at all, NOT whatever breaks.

Any guidance or updated documentation references for handling VoIP pushes in iOS 18 would be greatly appreciated.

The next step here is to reproduce the problem on a test device, then trigger and collect a sysdiagnose, open the system log archive, and then dig into the log to "see what happened". callservicesd has good logging diagnostics, so it's not difficult to trace a VoIP push from its arrival in APNSD all the way to its full processing by callservicesd. I've done this kind of analysis on a few different forum threads, see here, here, and here for examples.

A few notes on that process:

  • If this has been happening for a while, then it's very likely that callservicesd has stopped delivering pushes to your app due to reporting failures. Delete and reinstall the app to reset that.

  • The Phone (General) debug profile will provide more detailed logging from callservicesd. It's not necessary to track basic push handling, but it can be helpful, particularly for more complicated issues.

Focussing on the log analysis process:

  • A sysdiagnose log archive contains hours and even days of data, so it's not necessary to be exact about when you trigger the log.

  • Rebooting the device purges significant log data, so don't reboot until you've collected the data.

  • It's easy to overlook the "Showing" button in the bottom left of Console.app; it controls the time frame you're looking at.

  • Right-clicking on any log field will give you options for including/excluding data based on the field content, and you can also edit the entry that creates in the top right "search" field. This makes it easy to quickly narrow down to what you're actually interested in.

Hopefully, that's enough to get you started. Please let me know what you find or if you have any questions.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

pushkit and callkit
 
 
Q