CallManager.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. //
  2. // CallManager.swift
  3. // flutter_callkit_incoming
  4. //
  5. // Created by Hien Nguyen on 07/10/2021.
  6. //
  7. import Foundation
  8. import CallKit
  9. @available(iOS 10.0, *)
  10. class CallManager: NSObject {
  11. private let callController = CXCallController()
  12. private var sharedProvider: CXProvider? = nil
  13. private(set) var calls = [Call]()
  14. func setSharedProvider(_ sharedProvider: CXProvider) {
  15. self.sharedProvider = sharedProvider
  16. }
  17. func startCall(_ data: Data) {
  18. let handle = CXHandle(type: self.getHandleType(data.handleType), value: data.getEncryptHandle())
  19. let uuid = UUID(uuidString: data.uuid)
  20. let startCallAction = CXStartCallAction(call: uuid!, handle: handle)
  21. startCallAction.isVideo = data.type > 0
  22. let callTransaction = CXTransaction()
  23. callTransaction.addAction(startCallAction)
  24. //requestCall
  25. self.requestCall(callTransaction, action: "startCall", completion: { _ in
  26. let callUpdate = CXCallUpdate()
  27. callUpdate.remoteHandle = handle
  28. callUpdate.supportsDTMF = data.supportsDTMF
  29. callUpdate.supportsHolding = data.supportsHolding
  30. callUpdate.supportsGrouping = data.supportsGrouping
  31. callUpdate.supportsUngrouping = data.supportsUngrouping
  32. callUpdate.hasVideo = data.type > 0 ? true : false
  33. callUpdate.localizedCallerName = data.nameCaller
  34. self.sharedProvider?.reportCall(with: uuid!, updated: callUpdate)
  35. })
  36. }
  37. func muteCall(call: Call, isMuted: Bool) {
  38. let muteAction = CXSetMutedCallAction(call: call.uuid, muted: isMuted)
  39. let callTransaction = CXTransaction()
  40. callTransaction.addAction(muteAction)
  41. self.requestCall(callTransaction, action: "muteCall")
  42. }
  43. func holdCall(call: Call, onHold: Bool) {
  44. let muteAction = CXSetHeldCallAction(call: call.uuid, onHold: onHold)
  45. let callTransaction = CXTransaction()
  46. callTransaction.addAction(muteAction)
  47. self.requestCall(callTransaction, action: "holdCall")
  48. }
  49. func endCall(call: Call) {
  50. let endCallAction = CXEndCallAction(call: call.uuid)
  51. let callTransaction = CXTransaction()
  52. callTransaction.addAction(endCallAction)
  53. //requestCall
  54. self.requestCall(callTransaction, action: "endCall")
  55. }
  56. func connectedCall(call: Call) {
  57. let callItem = self.callWithUUID(uuid: call.uuid)
  58. callItem?.connectedCall(completion: nil)
  59. let answerAction = CXAnswerCallAction(call: call.uuid)
  60. let transaction = CXTransaction(action: answerAction)
  61. callController.request(transaction) { error in
  62. if let error = error {
  63. print("Error answering call: \(error.localizedDescription)")
  64. } else {
  65. // Call successfully answered
  66. }
  67. }
  68. }
  69. func endCallAlls() {
  70. let calls = callController.callObserver.calls
  71. for call in calls {
  72. let endCallAction = CXEndCallAction(call: call.uuid)
  73. let callTransaction = CXTransaction()
  74. callTransaction.addAction(endCallAction)
  75. self.requestCall(callTransaction, action: "endCallAlls")
  76. }
  77. }
  78. func activeCalls() -> [[String: Any]] {
  79. let calls = callController.callObserver.calls
  80. var json = [[String: Any]]()
  81. for call in calls {
  82. let callItem = self.callWithUUID(uuid: call.uuid)
  83. if(callItem != nil){
  84. var item: [String: Any] = callItem!.data.toJSON()
  85. item["accepted"] = callItem?.hasConnected
  86. json.append(item)
  87. }else {
  88. let item: [String: String] = ["id": call.uuid.uuidString]
  89. json.append(item)
  90. }
  91. }
  92. return json
  93. }
  94. func setHold(call: Call, onHold: Bool) {
  95. let handleCall = CXSetHeldCallAction(call: call.uuid, onHold: onHold)
  96. let callTransaction = CXTransaction()
  97. callTransaction.addAction(handleCall)
  98. //requestCall
  99. }
  100. private func requestCall(_ transaction: CXTransaction, action: String, completion: ((Bool) -> Void)? = nil) {
  101. callController.request(transaction){ error in
  102. if let error = error {
  103. //fail
  104. print("Error requesting transaction: \(error)")
  105. }else {
  106. if(action == "startCall"){
  107. //TODO: push notification for Start Call
  108. }else if(action == "endCall" || action == "endCallAlls"){
  109. //TODO: push notification for End Call
  110. }
  111. completion?(error == nil)
  112. print("Requested transaction successfully: \(action)")
  113. }
  114. }
  115. }
  116. private func getHandleType(_ handleType: String?) -> CXHandle.HandleType {
  117. var typeDefault = CXHandle.HandleType.generic
  118. switch handleType {
  119. case "number":
  120. typeDefault = CXHandle.HandleType.phoneNumber
  121. break
  122. case "email":
  123. typeDefault = CXHandle.HandleType.emailAddress
  124. default:
  125. typeDefault = CXHandle.HandleType.generic
  126. }
  127. return typeDefault
  128. }
  129. static let callsChangedNotification = Notification.Name("CallsChangedNotification")
  130. var callsChangedHandler: (() -> Void)?
  131. func callWithUUID(uuid: UUID) -> Call?{
  132. guard let idx = calls.firstIndex(where: { $0.uuid == uuid }) else { return nil }
  133. return calls[idx]
  134. }
  135. func addCall(_ call: Call){
  136. calls.append(call)
  137. call.stateDidChange = { [weak self] in
  138. guard let strongSelf = self else { return }
  139. strongSelf.callsChangedHandler?()
  140. strongSelf.postCallNotification()
  141. }
  142. callsChangedHandler?()
  143. postCallNotification()
  144. }
  145. func removeCall(_ call: Call){
  146. guard let idx = calls.firstIndex(where: { $0 === call }) else { return }
  147. calls.remove(at: idx)
  148. callsChangedHandler?()
  149. postCallNotification()
  150. }
  151. func removeAllCalls() {
  152. calls.removeAll()
  153. callsChangedHandler?()
  154. postCallNotification()
  155. }
  156. private func postCallNotification(){
  157. NotificationCenter.default.post(name: type(of: self).callsChangedNotification, object: self)
  158. }
  159. }