| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- //
- // CallManager.swift
- // flutter_callkit_incoming
- //
- // Created by Hien Nguyen on 07/10/2021.
- //
- import Foundation
- import CallKit
- @available(iOS 10.0, *)
- class CallManager: NSObject {
-
- private let callController = CXCallController()
- private var sharedProvider: CXProvider? = nil
- private(set) var calls = [Call]()
-
-
- func setSharedProvider(_ sharedProvider: CXProvider) {
- self.sharedProvider = sharedProvider
- }
-
- func startCall(_ data: Data) {
- let handle = CXHandle(type: self.getHandleType(data.handleType), value: data.getEncryptHandle())
- let uuid = UUID(uuidString: data.uuid)
- let startCallAction = CXStartCallAction(call: uuid!, handle: handle)
- startCallAction.isVideo = data.type > 0
- let callTransaction = CXTransaction()
- callTransaction.addAction(startCallAction)
- //requestCall
- self.requestCall(callTransaction, action: "startCall", completion: { _ in
- let callUpdate = CXCallUpdate()
- callUpdate.remoteHandle = handle
- callUpdate.supportsDTMF = data.supportsDTMF
- callUpdate.supportsHolding = data.supportsHolding
- callUpdate.supportsGrouping = data.supportsGrouping
- callUpdate.supportsUngrouping = data.supportsUngrouping
- callUpdate.hasVideo = data.type > 0 ? true : false
- callUpdate.localizedCallerName = data.nameCaller
- self.sharedProvider?.reportCall(with: uuid!, updated: callUpdate)
- })
- }
-
- func muteCall(call: Call, isMuted: Bool) {
- let muteAction = CXSetMutedCallAction(call: call.uuid, muted: isMuted)
- let callTransaction = CXTransaction()
- callTransaction.addAction(muteAction)
- self.requestCall(callTransaction, action: "muteCall")
- }
-
- func holdCall(call: Call, onHold: Bool) {
- let muteAction = CXSetHeldCallAction(call: call.uuid, onHold: onHold)
- let callTransaction = CXTransaction()
- callTransaction.addAction(muteAction)
- self.requestCall(callTransaction, action: "holdCall")
- }
-
- func endCall(call: Call) {
- let endCallAction = CXEndCallAction(call: call.uuid)
- let callTransaction = CXTransaction()
- callTransaction.addAction(endCallAction)
- //requestCall
- self.requestCall(callTransaction, action: "endCall")
- }
-
- func connectedCall(call: Call) {
- let callItem = self.callWithUUID(uuid: call.uuid)
- callItem?.connectedCall(completion: nil)
-
- let answerAction = CXAnswerCallAction(call: call.uuid)
- let transaction = CXTransaction(action: answerAction)
- callController.request(transaction) { error in
- if let error = error {
- print("Error answering call: \(error.localizedDescription)")
- } else {
- // Call successfully answered
- }
- }
- }
-
- func endCallAlls() {
- let calls = callController.callObserver.calls
- for call in calls {
- let endCallAction = CXEndCallAction(call: call.uuid)
- let callTransaction = CXTransaction()
- callTransaction.addAction(endCallAction)
- self.requestCall(callTransaction, action: "endCallAlls")
- }
- }
-
- func activeCalls() -> [[String: Any]] {
- let calls = callController.callObserver.calls
- var json = [[String: Any]]()
- for call in calls {
- let callItem = self.callWithUUID(uuid: call.uuid)
- if(callItem != nil){
- var item: [String: Any] = callItem!.data.toJSON()
- item["accepted"] = callItem?.hasConnected
- json.append(item)
- }else {
- let item: [String: String] = ["id": call.uuid.uuidString]
- json.append(item)
- }
- }
- return json
- }
-
-
- func setHold(call: Call, onHold: Bool) {
- let handleCall = CXSetHeldCallAction(call: call.uuid, onHold: onHold)
- let callTransaction = CXTransaction()
- callTransaction.addAction(handleCall)
- //requestCall
- }
-
-
- private func requestCall(_ transaction: CXTransaction, action: String, completion: ((Bool) -> Void)? = nil) {
- callController.request(transaction){ error in
- if let error = error {
- //fail
- print("Error requesting transaction: \(error)")
- }else {
- if(action == "startCall"){
- //TODO: push notification for Start Call
- }else if(action == "endCall" || action == "endCallAlls"){
- //TODO: push notification for End Call
- }
- completion?(error == nil)
- print("Requested transaction successfully: \(action)")
- }
- }
- }
-
-
- private func getHandleType(_ handleType: String?) -> CXHandle.HandleType {
- var typeDefault = CXHandle.HandleType.generic
- switch handleType {
- case "number":
- typeDefault = CXHandle.HandleType.phoneNumber
- break
- case "email":
- typeDefault = CXHandle.HandleType.emailAddress
- default:
- typeDefault = CXHandle.HandleType.generic
- }
- return typeDefault
- }
-
-
- static let callsChangedNotification = Notification.Name("CallsChangedNotification")
- var callsChangedHandler: (() -> Void)?
-
- func callWithUUID(uuid: UUID) -> Call?{
- guard let idx = calls.firstIndex(where: { $0.uuid == uuid }) else { return nil }
- return calls[idx]
- }
-
- func addCall(_ call: Call){
- calls.append(call)
- call.stateDidChange = { [weak self] in
- guard let strongSelf = self else { return }
- strongSelf.callsChangedHandler?()
- strongSelf.postCallNotification()
- }
- callsChangedHandler?()
- postCallNotification()
- }
-
- func removeCall(_ call: Call){
- guard let idx = calls.firstIndex(where: { $0 === call }) else { return }
- calls.remove(at: idx)
- callsChangedHandler?()
- postCallNotification()
- }
-
- func removeAllCalls() {
- calls.removeAll()
- callsChangedHandler?()
- postCallNotification()
- }
-
- private func postCallNotification(){
- NotificationCenter.default.post(name: type(of: self).callsChangedNotification, object: self)
- }
-
-
- }
|