Skip to content

Commit 9650a10

Browse files
committed
Merge branch '184-platformexceptionunavailable-end-call-failed-the-operation-couldnt-be-completed-comapplecallkiterrorrequesttransaction-error-4-null-null'
2 parents d9eda84 + af8e687 commit 9650a10

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.1
2+
3+
* Fix: [iOS] Race condition ending call remotely and locally results in a "End Call Failed: The operation couldn’t be completed." error. [Issue #184](https://github.com/cybex-dev/twilio_voice/issues/184)
4+
15
## 0.2.0+1
26

37
* Fix: [Web] `window.localStorage` deprecated members

ios/Classes/SwiftTwilioVoicePlugin.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import TwilioVoice
66
import CallKit
77
import UserNotifications
88

9-
public class SwiftTwilioVoicePlugin: NSObject, FlutterPlugin, FlutterStreamHandler, PKPushRegistryDelegate, NotificationDelegate, CallDelegate, AVAudioPlayerDelegate, CXProviderDelegate {
9+
public class SwiftTwilioVoicePlugin: NSObject, FlutterPlugin, FlutterStreamHandler, PKPushRegistryDelegate, NotificationDelegate, CallDelegate, AVAudioPlayerDelegate, CXProviderDelegate, CXCallObserverDelegate {
10+
let callObserver = CXCallObserver()
1011

1112
final let defaultCallKitIcon = "callkit_icon"
1213
var callKitIcon: String?
@@ -44,6 +45,8 @@ public class SwiftTwilioVoicePlugin: NSObject, FlutterPlugin, FlutterStreamHand
4445
var userInitiatedDisconnect: Bool = false
4546
var callOutgoing: Bool = false
4647

48+
private var activeCalls: [UUID: CXCall] = [:]
49+
4750
static var appName: String {
4851
get {
4952
return (Bundle.main.infoDictionary!["CFBundleName"] as? String) ?? "Define CFBundleName"
@@ -65,6 +68,7 @@ public class SwiftTwilioVoicePlugin: NSObject, FlutterPlugin, FlutterStreamHand
6568

6669
//super.init(coder: aDecoder)
6770
super.init()
71+
callObserver.setDelegate(self, queue: DispatchQueue.main)
6872

6973
callKitProvider.setDelegate(self, queue: nil)
7074
_ = updateCallKitIcon(icon: defaultIcon)
@@ -537,6 +541,22 @@ public class SwiftTwilioVoicePlugin: NSObject, FlutterPlugin, FlutterStreamHand
537541
completion()
538542
}
539543
}
544+
545+
// MARK: CXCallObserverDelegate
546+
public func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
547+
let uuid = call.uuid
548+
549+
if call.hasEnded {
550+
activeCalls.removeValue(forKey: uuid) // Remove ended calls
551+
} else {
552+
activeCalls[uuid] = call // Add or update call
553+
}
554+
}
555+
556+
// Check if a call with a given UUID exists
557+
func isCallActive(uuid: UUID) -> Bool {
558+
return activeCalls[uuid] != nil
559+
}
540560

541561
func incomingPushHandled() {
542562
if let completion = self.incomingPushCompletionCallback {
@@ -890,6 +910,13 @@ public class SwiftTwilioVoicePlugin: NSObject, FlutterPlugin, FlutterStreamHand
890910

891911
self.sendPhoneCallEvents(description: "LOG|performEndCallAction method invoked", isError: false)
892912

913+
// check if call is still active, preventing a race condition ending the call throwing an End Call Failed transaction error 4 error
914+
guard isCallActive(uuid: uuid) else {
915+
print("Call not found or already ended. Skipping end request.")
916+
self.sendPhoneCallEvents(description: "Call Ended", isError: false)
917+
return
918+
}
919+
893920
let endCallAction = CXEndCallAction(call: uuid)
894921
let transaction = CXTransaction(action: endCallAction)
895922

0 commit comments

Comments
 (0)