After updating iOS 18 CXCall is giving wrong values in hasConnected and hasEnded when user reject the call

Dear Apple team, I would like to report a problem that started after update my iPhone to iOS 18.0.1. When user receives a call and reject, CXCall is giving wrong values compared the previous version of iOS (minor of 18).

In iOS 17.7, we received this values:

hasConnected = false
hasEnded = true

iOS 18.0.1 we received 2 CXCall events:

first event

hasConnected = true
hasEnded = false

second event

hasConnected = true
hasEnded = true

This behaviour is strange and not intuitive, and if we check the documentation, don`t make sense: A call is considered connected when both caller and callee can start communicating and A call is considered ended when the user disconnects or all other callers disconnect.

Our code is very simple and use callObserver function to make the flow:

public func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
        if call.hasConnected, !call.hasEnded {
            //GoToViewControllerX
        }
        if call.hasEnded {
            //DoSomething
        }
    }

With the behavior of iOS 18 the project will enter in first conditional and then will enter in second conditional.

I need some help or some instruction because the intention ir only enter in first conditional if the call really happens.

Have you filed a bug on this and, if so, what is the bug number?

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

iOS 18.0.1 we received 2 CXCall events:

What's the time gap between those events? Assuming that the time gap is relatively long, then I suspect this is actually being caused by live voicemail putting the call into a state that the existing API doesn't really account for.

Note that if this IS live voicemail, then the "correct" behavior is effectively undefined. At a purely technical level, this is in fact EXACTLY what happened:

hasConnected = true
hasEnded = false

That is, "Phone.app" connected the call (so it could start receiving audio from the other party) but choose not to play the audio it recorded (converting it to text instead). The system obviously has custom UI support for this process, but any voip app could choose to implement the same logical flow. The fact that a voip app has connected a call doesn't mean the app is actually required to record or play anything.

Now, it's entirely possible that the engineering team may choose to change the behavior here in a way that better matches your expectations, but I want to be clear that the assumption that CallKit requires voip apps (including Phnone.app) to work a particular way in every detail is simply wrong.

The larger issue here is with the nature of the documentation here:

if we check the documentation, don`t make sense: A call is considered connected when both caller and callee can start communicating and A call is considered ended when the user disconnects or all other callers disconnect.

What the documentation is stating there is our INTENTION for that state, NOT any "requirement" that's tied to reality. To read it as requiring voip apps to behave in a specific way is to misunderstand the relation ship between voip app and CallKit.

The issue here is that CallKit is fundamentally a user interface framework, not a full "call management system". CallKit doesn't actually "know" anything about what's REALLY happening on the ACTUAL call. You'll notice how the phrase "is considered" occurs again and again with all of these call states. That's because what actually controls the state of these flags is the decision of the app that actually owns each call.

That is, in purely technical terms, a call is connected when the controlling app says it's connected. I suspect that most apps will switch to "connected":

"...when both caller and callee can start communicating"

...but nothing in the system ACTUALLY requires them to do and, more importantly, an app choosing to change state under different conditions isn't actually doing anything "wrong" or breaking the API contract.

These issue lead me to here:

Our code is very simple and use callObserver function to make the flow:

From the general context, it's clear that you're using CXCallObserver to try and monitor/track the call activity of other apps, particularly Phone.app. While this is technically possible, this is not a use case CXCallObserver or CallKit was ever designed to support. The point of CallKit is to provide an interface framework that manages the specialized UI and audio needs of voip apps. CXCallObserver exists because CallKit apps were always going to have some "awareness" of other active calls (for example, because the user is/can switch between calls) and providing a SMALL amount of additional visibility about the "currently active call set" does mean that some apps are better able to customize their own call flow behavior. Using it for broader tracking isn't something the system intentionally supports.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

After updating iOS 18 CXCall is giving wrong values in hasConnected and hasEnded when user reject the call
 
 
Q