I am developing an application that uses NetworkExtension (Local PUSH function) And VoIP(APNs) PUSH. Nowadays, I found a problem on this app doesn't handle incoming call of Local PUSH when receiving a Local PUSH after receiving an APNs PUSH.
My confimation result of my app and server log is below.
11:00 AM:
my server(PBX) requests a VoIP(APNs) PUSH notification to the APNs. But my app does not receive the VoIP(APNs) PUSH. At this time, my app is running on LAN (Wi-Fi without internet connection), as a result, NetworkExtension was running. so I think this is normal behaviour.
14:55:11 PM:
There is an incoming call from the my server(PBX) via local net, and NetworkExtension calls iOS API(API name is reportIncomingCall). However, iOS does not call the delegate didReceiveIncomingCallWithUserInfo for the reportIncomingCall.
14:55:11 PM:
At almost the same time, iOS calls the delegate cdidReceiveIncomingPushWithPayload of VoIP PUSH. (instead of call the delegate didReceiveIncomingCallWithUserInfo for the reportIncomingCall?) And the content of this VoIP(APNs) PUSH was the incoming call at "11:00 AM".
In other words, the VoIP(APNs) PUSH at 11:00 AM is stuck inside iOS, and at 14:55:11 PM, from NetworkExtension reports it.
I feel there is a problem on iOS doesn't handle incoming call of Local PUSH when receiving a Local PUSH after receiving an VoIP(APNs) PUSH. Would you tell me Apple's opioion about this?
If this is known problem, Please tell me about it.
my server(PBX) requests a VoIP(APNs) PUSH notification to the APNs. But my app does not receive the VoIP(APNs) PUSH. At this time, my app is running on LAN (Wi-Fi without internet connection), as a result, NetworkExtension was running. so I think this is normal behaviour.
Just to clarify here, the system doesn't differentiate or attempt any kind of de-duplication or arbitration between VOIP pushes and the network extension. The voip push can fail to reach your device because the device is on an isolated network, but that's no different than any other failed voip push.
14:55:11 PM: There is an incoming call from the my server(PBX) via local net, and NetworkExtension calls iOS API(API name is reportIncomingCall). However, iOS does not call the delegate didReceiveIncomingCallWithUserInfo for the reportIncomingCall.
14:55:11 PM: At almost the same time, iOS calls the delegate cdidReceiveIncomingPushWithPayload of VoIP PUSH. (instead of call the delegate didReceiveIncomingCallWithUserInfo for the reportIncomingCall?) And the content of this VoIP(APNs) PUSH was the incoming call at "11:00 AM".
Looking at the flow above, my big question is exactly how you "know" what you "know" here. That is, you're describing a chain of behavior above, but how exactly did you determine that flow?
Notably, while callservicesd handles the final delivery for both of these APIs, the paths than handle that delivery are separated in a way that should make it impossible for messages to be delivered to the "wrong" path.
One question on this point:
At this time, my app is running on LAN (Wi-Fi without internet connection), as a result, NetworkExtension was running. so I think this is normal behaviour.
Did your local push connectivity receive this case? If not, why not?
Similarly, is there any way you could have been wrong about exactly what delegates got called a what point in time? What you're describing doesn't make sense, but there is a slightly different failure I have seen in that past which looks somewhat similar.
The issue here is that NEAppPushManager has a MUCH shorter "wake window" PKPushRegistry. For historical reason, PKPushRegistry can actually keep the app awake for a fairly long period of time (several seconds), enough time that a sequence like this can happen:
- PKPushRegistry wakes app up and delivers push.
- App reports call to CallKit (as required) and returns from the delegate.
- PKPushRegistry keeps the app awake.
- CallKit call finishes starts and initialization, keeping the app awake.
The critical point her is that CallKit call creation is inherently asynchronous, so new call doesn't actually "keep the app awake" until a short time AFTER it's created. PKPushRegistry ends up "covering up" that time gap, by keeping the app awake on it's own.
However, (arguably, correctly) NEAppPushManager does NOT do this. In the EXACT same sequence above, what can happen is the following:
- NEAppPushManager wakes app up and delivers push.
- App reports call to CallKit (as required) and returns from the delegate.
- Call initialization starts (enough to prevent app termination).
- App suspends (because nothing is keeping it awake).
- ...time passes...
- "something else" wakes the app up (for example, a voip push), and the app the proceeds with it's "normal" call logic, generally not realizing that #5 has occurred.
In any case, the solution here is that voip apps should start their own background task inside the call delegate and end that background task at some later point, after the call has started. Note that this approach should be used for BOTH PKPushRegistry and NEAppPushManager, as it ensures the app has a reliable lifetime regardless of system behavior.
In other words, the VoIP(APNs) PUSH at 11:00 AM is stuck inside iOS, and at 14:55:11 PM, from NetworkExtension reports it.
Have you captured a sysdiagnose of the issue and what does the console log from that sysdiagnose show? Bug number?
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware