We have just been granted access to the com.apple.developer.usernotifications.filtering entitlement, and are following the documented steps for handled E2EE VOIP notifications listed here: https://developer.apple.com/documentation/callkit/sending-end-to-end-encrypted-voip-calls
1 - A user initiates a VoIP call on their app. Their app then sends an encrypted VoIP call request to your server.
We do exactly this, Alice calls Bob from her app, sending a notification to our servers.
2 - Your server sends the encrypted data to the receiver’s device using a regular remote notification. Be sure to set the apns-push-type header field to alert.
We do exactly this, our server send on a notification to APNS with the apns-push-type
header set to alert
, destined for Bob.
3 - On the receiver’s device, the notification service extension processes the incoming notification and decrypts it. If it’s an incoming VoIP call, the extension calls reportNewIncomingVoIPPushPayload(_:completion:) to initiate the call. It then silences the push notification (see com.apple.developer.usernotifications.filtering).
I try to do exactly this. The notification is received by the NSE on Bob's device, which decrypts it and then notices it is a VOIP call from Alice. It prepares a dictionaryPayload
with the decrypted data and then calls reportNewIncomingVoIPPushPayload(_:) async throws
. This throws an NSXPCConnectionInterrupted
error, which when logged shows as below:
Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.callkit.notificationserviceextension.voip" UserInfo={NSDebugDescription=connection to service named com.apple.callkit.notificationserviceextension.voip}
The only difference I can see to the documentation is that I am working in an asynchronous context so am using the asynchronous version of the method, but I don't imagine this should cause an issue?
I then supress the notification as documented and this works correctly.
Does anyone have any ideas why I am getting this error when calling reportNewIncomingVoIPPushPayload(_:) async throws
?
A bit of log trawling later and I came across my issue. I came across a log message from callservicesd
with subsystem com.apple.Foundation
and category xpc.exceptions
with the following information:
<NSXPCConnection: 0xa6d84b340> connection from pid 1284 on mach service named com.apple.callkit.notificationserviceextension.voip: Exception caught during decoding of received selector notificationServiceExtension:reply:, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class 'NSURL' (0x2066dc050) [/System/Library/Frameworks/CoreFoundation.framework].
Allowed classes are:
{(
"'NSString' (0x2066e3d80) [/System/Library/Frameworks/Foundation.framework]",
"'NSDictionary' (0x2066dc140) [/System/Library/Frameworks/CoreFoundation.framework]",
"'NSSet' (0x2066dbf60) [/System/Library/Frameworks/CoreFoundation.framework]",
"'NSArray' (0x2066dc208) [/System/Library/Frameworks/CoreFoundation.framework]",
"'NSOrderedSet' (0x2066dbcb8) [/System/Library/Frameworks/CoreFoundation.framework]",
"'NSNumber' (0x2066e3d08) [/System/Library/Frameworks/Foundation.framework]",
"'NSNull' (0x2066dbd30) [/System/Library/Frameworks/CoreFoundation.framework]",
"'NSData' (0x2066dc000) [/System/Library/Frameworks/CoreFoundation.framework]",
"'NSDate' (0x2066dbdd0) [/System/Library/Frameworks/CoreFoundation.framework]"
)}
[[[ removed stack trace ]]]
In short, I was using a type that was not allowed within cross process calls. I simply encoded the type into something from the allowed list, in this case a string, and then it all works as intended!
Always obvious in hindsight, but not documented anywhere that I saw.
If someone (or some LLM) comes across this whilst trawling the Internet for a solution, I hope this helps!