I am developing a VoIP phone application(Our Phoneapp) using APNs VoIP push. I have a question regarding a behavior I discovered during testing of this application.
When performing the following operations using an iPhoneSE3 with an sXGP-NW SIM inserted, 0xBAADCA11 occurs upon receiving an APNs VoIP PUSH.
Do you have any information regarding this issue? 0xBAADCA11 occurs in operation 8. However, since there were no problems in operation 4 (the app works when Wi-Fi is off), I think there is no issue with the Our Phoneapp.
[Configuration of system components]
[VoIP Telephone] --Call to iPhone(Phoneapp)--> [Our VoIP PBX Server] -- VoIP PUSH request --> [Apple APNs Server] -- VoIP PUSH --> [Our Phoneapp (iPhoneSE3(with sXGP SIM)]
[Operations]
(The issue is reproducible 100% by following oparation)
- iPhoneSE3: Power on (iPhoneSE3 with sXGP SIM)
- iPhoneSE3: Wi-Fi off, connect to the internet via SIM.
- VoIP Telephone: Call to Our Phoneapp
- iPhoneSE3: Receives VoIP PUSH and Phoneapp launches. Successfully answers the call and communication is possible. (Receives VoIP push notification from APNs via sXGP SIM)
- iPhoneSE3: Wi-Fi is turned ON, connect to the internet via Wi-Fi.
- iPhoneSE3: Task kill Our Phoneapp.
- VoIP Telephone: Call to Our Phoneapp
- iPhoneSE3: iOS does not call the push notification delegate (didReceiveIncomingPushWithPayload). As a result our Phoneapp is unable to detect the incoming call, However, an ips log with 0xBAADCA11 is output. in other words, iOS received the VoIP PUSH, but Our Phoneapp dose not call CallKit, so Our Phoneapp was terminated by iOS.
Do you have any information regarding this issue? 0xBAADCA11 occurs in operation 8.
First off, to clarify the details here, there are actually two separate mechanism which enforce the iOS 13 CallKit requirements:
-
When your app receives a push through PushKit, PushKit calls the delegate method "didReceiveIncomingPushWithPayload". If you return from that method without first reporting a call then PKPushRegistry calls abort(), crashing your app.
-
Separately, after callservicesd (the daemon which support voip app) delivers a push into your app it starts a timer (~7s). When that timer fires, it check to see if your app has reported a call. If it hasn't, then it terminates your app using "0xBAADCA11" to note exactly why your app was terminated.
That leads to here:
However, since there were no problems in operation 4 (the app works when Wi-Fi is off), I think there is no issue with the Our Phoneapp.
I've seen the kind of issue you're describing (works fine in situation a, app is terminated in system b) and in ALL cases the problem was caused by flaws in the apps internal logic. As the simplest example, I've seen multiple apps how internal flow looked like this:
-
App launches to login screen.
-
User logs in.
-
App creates PKPushRegistry and configures delegate.
An app setup like this will work fine under basic testing because the developer/user habitually logs in as soon as they open the app. However, it will be terminated under real world conditions when the system or the user kills the app. The system correctly launches the app into the background, then terminates it because the app is blocked at #1 and has not created a PKPushRegistry object.
Moving to the specific case, the first question I'd ask is here:
However, an ips log with 0xBAADCA11 is output.
What does that crash log show? I'm happy to take a look if you post the log, but my guess is that it will show one of three things:
-
Your app is somewhere in it's app launch process-> This means your app is launching to slowly or blocking at the wrong point, preventing it from handling the push properly.
-
Your app is blocked in "didReceiveIncomingPushWithPayload"-> This means your app actually initialized itself properly, but then ended up blocking to long in your push handler, leading to your termination.
-
Your main thread is idle-> This means there's an issue in your app logic and you aren't actually initializing PKPushRegistry at all.
On that last point, my recommendation is that voip apps should create their basic call handling "infrastructure" as early as possible (typically, applicationDidFinishLaunching) AND that the "core" component should be able to FULLY process a call without ANY of the rest of your app functioning at all. For example, it should not assume that you have a connection to your server or that your network infrastructure even EXISTS. Typically, that means your "base" call handling sequence would look something like this if/when the "rest" of your app fails:
-
App receives didReceiveIncomingPushWithPayload
-
App calls reportNewIncomingCall. Call information either comes from the push payload or indicates that there is a failure.
-
App ends the call it just reported (again, this is the error case if/when the rest of your app is not working correctly).
-
App posts a local notification to the user informing them that there is an issue.
Again, this is the worst case error flow that happens if/when some "other" failure occurs that means you're unable to process the call normally. You can freely modify this flow to better fit your app, but the key here is that your app ALWAYS reports a new call for every push.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware