iOS 27 Public Beta 6: CallKit UI remains after ending two outgoing calls in modified Apple Speakerbox sample

Summary

On an iPhone 17 running iOS 27 Public Beta 6, the system CallKit UI remains visible after ending two outgoing calls individually.

This is reproducible using Apple's “Making and Receiving VoIP Calls with CallKit” sample (Speakerbox), with only two minimal changes to support multiple simultaneous calls. After both calls end, Speakerbox displays “No Calls”, but the system CallKit UI still shows 111, and the Dynamic Island retains a call-related status.

Environment

  • Device: iPhone 17 (physical device)
  • OS: iOS 27 Public Beta 6
  • App: Apple's Speakerbox sample with the modifications below
  • Backend: None. The sample's original simulated calls are used; no external VoIP SDK is involved.

Changes to the original sample

Only two files were modified.

1. ProviderDelegate.swift

Added:

providerConfiguration.maximumCallGroups = 3

The original setting remains unchanged:

providerConfiguration.maximumCallsPerCallGroup = 1

2. SpeakerboxCallManager.swift

Before starting a new outgoing call, hold existing calls that are not already on hold. The hold actions and new start action are submitted in the same transaction:

let transaction = CXTransaction()

for call in calls where !call.isOnHold {
    transaction.addAction(
        CXSetHeldCallAction(call: call.uuid, onHold: true)
    )
}

transaction.addAction(startCallAction)
requestTransaction(transaction)

No changes were made to the simulated connection timing, startedConnectingAt/connectedAt reporting, CXEndCallAction handling, call removal, or audio handling.

The original end-call handler finds the call by UUID, calls endSpeakerboxCall(), fulfills the end action, and removes the call from the app's list.

Steps to reproduce

  1. Launch the modified Speakerbox sample.
  2. Create an outgoing call to 111.
  3. Create a second outgoing call to 222. The first call is placed on hold.
  4. Wait until Speakerbox shows 111 — On Hold and 222 — Active, with call durations displayed.
  5. In Speakerbox, select 222 - End Call.
  6. Select 111 - End Call.
  7. Confirm that Speakerbox displays “No Calls”.
  8. Open the app switcher and inspect the system CallKit UI. Also inspect the Dynamic Island.
  9. Open the remaining system call UI and tap End.

Expected result

After both calls end, the system should no longer display an ongoing call in the CallKit UI or Dynamic Island.

Actual result

  • Speakerbox displays “No Calls”.
  • The system CallKit UI continues to display the first call, 111.
  • The Dynamic Island continues to show a call-related “Hold” status.
  • Tapping End in the remaining system call UI does not clear the residual state during the recording.
  • The issue occurs even after waiting for both simulated calls to connect before ending them.

This is the system-provided CallKit UI, not an active-call view implemented by the sample app.

Reproduction video

Recording: 4b03d30e507b874d9c19c0523632e9d6.mp4

  • 00:24–00:26 (approximately): Both calls are present; 111 is on hold and 222 is active.
  • 00:26–00:31 (approximately): End 222, then end 111. Speakerbox displays “No Calls”.
  • 00:31–01:03 (approximately): The system CallKit UI and Dynamic Island retain the call state despite further attempts to end it.

Questions

Is this an iOS 27 regression, or is additional lifecycle handling required when extending Speakerbox to support multiple calls?

Please advise what additional diagnostics would help investigate why the system UI retains an ongoing-call state after both calls have been ended using the sample's original end-call handling.

Source and video downloads

https://github.com/willbin/callkit-ios27-repro/releases/tag/repro-v1

I used AI to polish the content and the description is correct.

Is this an iOS 27 regression, or is additional lifecycle handling required when extending Speakerbox to support multiple calls?

It's a bug (r.185143623). There have actually been a number of otherwise unrelated bugs which all create the same result (InCallService's lingering), which always complicates fully addressing an issue like this. If you haven't already, please file a bug on this and then post the bug number back here.

Please advise what additional diagnostics would help investigate why the system UI retains an ongoing-call state after both calls have been ended using the sample's original end-call handling.

So, one thing to understand here is that the system UI you're seeing in an entirely separate app ("InCallService") whose only role is to present the call UI you see. Functionally, that means it's totally independent of your app, so the wrong kind of glitch can create exactly what you're seeing.

In terms of your own investigation, the main thing I would look at is whether or not CXCallObserver.calls lists a call after the call UI gets stuck. That call list is retrieved from callservicesd, so it’s telling you what "the system" knows about, not just your app.

Unfortunately, my guess is that it won't contain a call which means that there isn't really anything your app can do about it. Once callservicesd has destroyed "the call", there isn't really any connection from your app to InCallService, which means you don't have any ability to disrupt/alter InCallService.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

@DTS Engineer Please check.

Feedback number: 24737254 https://feedbackassistant.apple.com/feedback/24737254

Question 1: What is the fix plan for this issue, the iOS27 is coming soon.

btw, I also encountered another CallKit issue on iOS 27:

  1. Make a VoIP call.
  2. Receive a native call.
  3. The VoIP call (on my VoIP app) will be ended.
  4. On my iPhone 17, it works well. But on iPhone15, it will be ended.

Question 2: So, the same issue?

Question 1: What is the fix plan for this issue? The iOS 27 is coming soon.

It's being actively investigated, but given the timing of things, it's not going to be fixed in iOS 27.0.

Question 2: So, the same issue?

No, not at all. This is the first report I've seen of this, and in general, what you're describing sounds quite strange. In particular:

On my iPhone 17, it works well. But on iPhone 15, it will be ended.

…device-specific bugs are quite unusual in CallKit. Aside from a few new features (like translation) which have required specific hardware, its behavior is generally consistent across all system releases.

One thing to understand here that often confuses developers is that CallKit is fundamentally an interface framework, NOT a "calling" framework. The issue here is because of how "real" the call UI looks (because it is our call UI). Many developers tend to assume that CallKit is FAR more aware/involved with your app’s architecture than it actually is.

For example, you might think CallKit would end to "free up network resources", but CallKit will NOT do that because CallKit doesn't have ANY idea how your app actually works and doesn't actually require your app to do ANY networking[1].

Returning to the specific issue:

But on iPhone 15, it will be ended.

First off, have you reproduced the issue in Speakerbox, as that's the quickest way to immediately prove that this is a system issue, not an app bug? If Speakerbox fails then you should immediately file a bug, but my guess is that something else is going on here.

Assuming Speakerbox works fine, then the next step is to figure out what actually happened in your app. A few things to look for:

  • Was the call actually ended (leaving your app still running and functional) or was your app terminated/crashed? Both of those cases will look the same (your call ends), but they're obviously totally different scenarios.

  • If the call ended, take a closer look at exactly how it ended. I've seen several cases where the app was actually ending its own call, but didn't realize how the specific edge cases were playing out.

  • Pay very close attention to exactly how you’re interacting with the device and what exactly that "does". Working with CallKit means you're paying FAR more attention to the details of the call UI, which means you can end up triggering existing behaviors that you weren't even aware existed.

Expanding on that last point, I periodically get reports from developers complaining that pushing the lock button ends their call and assuming it's a bug. That very much ISN’T a bug, as this is something iOS has been doing since WELL before we introduced CallKit (possibly all the way back to the original iPhone). It’s always worked this way, they've just never paid enough attention to the call UI to notice.

As one other specific detail, I'd disable Bluetooth while testing this just to rule out a disruptive edge case. HFP (Hands Free Profile) accessories have a great deal of control over how the phone handles calls, including the ability to hang up calls, so an overlooked headset or head unit can generate all sorts of behaviors you might not expect. The easiest way to rule out that possibility is to turn off Bluetooth.

[1] This makes more sense in PushToTalk app, but it's theoretically possible to implement a VoIP app that ONLY used PushKit. The caller talks, his text is converted to text, that text is embedded in the push payload, and speech to text is then used to play it to the receiver after he answers.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

iOS 27 Public Beta 6: CallKit UI remains after ending two outgoing calls in modified Apple Speakerbox sample
 
 
Q