// MARK: CallKit & PushKit
extension AppDelegate: PKPushRegistryDelegate , CXProviderDelegate {
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
let deviceToken = pushCredentials.token.reduce("", {$0 + String(format: "%02X", $1) })
print("voip token is: \(deviceToken)")
UserDefaults.standard.set(deviceToken, forKey: "voipToken")
CometChat.registerTokenForPushNotification(token: deviceToken, settings: ["voip":true]) { (success) in
print("registerTokenForPushNotification voip: \(success)")
} onError: { (error) in
print("registerTokenForPushNotification error: \(error)")
}
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
if let userInfo = payload.dictionaryPayload as? [String : Any], let messageObject =
userInfo["message"], let dict = messageObject as? [String : Any] {
if let baseMessage = CometChat.processMessage(dict).0 {
switch baseMessage.messageCategory {
case .message: break
case .action: break
case .call:
if let call = baseMessage as? Call {
switch call.callStatus {
case .initiated:
self.activeCall = call
self.uuid = UUID()
if let name = (call.sender)?.name {
let config = CXProviderConfiguration(localizedName: "APNS + Callkit")
config.iconTemplateImageData = #imageLiteral(resourceName: "your_app_icon").pngData()
config.includesCallsInRecents = false
config.ringtoneSound = "ringtone.caf"
config.supportsVideo = true
provider = CXProvider(configuration: config)
provider?.setDelegate(self, queue: nil)
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: name.capitalized)
if call.callType == .video {
update.hasVideo = true
}else{
update.hasVideo = false
}
provider?.reportNewIncomingCall(with: self.uuid!, update: update, completion: { error in
if error == nil {
self.configureAudioSession()
}
})
}
case .ongoing, .unanswered, .rejected, .busy, .cancelled:
if self.activeCall != nil {
if self.cancelCall {
self.end(uuid: self.uuid!)
}
}
case .ended: break
@unknown default: break }
}
case .custom: break
@unknown default: break
}
}
}
}
internal func configureAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: [.mixWithOthers, .allowBluetooth, .defaultToSpeaker])
try AVAudioSession.sharedInstance().setActive(true)
} catch let error as NSError {
print(error)
}
}
func providerDidReset(_ provider: CXProvider) {
if let uuid = self.uuid {
onCall = true
provider.reportCall(with: uuid, endedAt: Date(), reason: .unanswered)
}
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
if let activeCall = activeCall {
startCall()
}
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "didRejectButtonPressed"), object: nil, userInfo: nil)
end(uuid: self.uuid!)
onCall = true
if let activeCall = activeCall {
CometChat.rejectCall(sessionID: activeCall.sessionID ?? "", status: .rejected, onSuccess: {(rejectedCall) in
DispatchQueue.main.async {
CometChatSnackBoard.display(message: "CALL_REJECTED".localized(), mode: .info, duration: .short)
}
}) { (error) in
DispatchQueue.main.async {
if let errorMessage = error?.errorDescription {
CometChatSnackBoard.display(message: "CALL_REJECTED".localized(), mode: .info, duration: .short)
}
}
}
provider.reportCall(with: self.uuid!, endedAt: Date(), reason: .remoteEnded)
}
action.fail()
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
print(#function)
}
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
action.fulfill()
print(#function)
}
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
print(#function)
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
print(#function)
}
func end(uuid: UUID) {
print("endUUID",uuid)
let endCallAction = CXEndCallAction(call: uuid)
let transaction = CXTransaction()
transaction.addAction(endCallAction)
requestTransaction(transaction, action: "")
}
func setHeld(uuid: UUID, onHold: Bool) {
print("setHeld",uuid)
let setHeldCallAction = CXSetHeldCallAction(call: uuid, onHold: onHold)
let transaction = CXTransaction()
transaction.addAction(setHeldCallAction)
requestTransaction(transaction, action: "")
}
internal func requestTransaction(_ transaction: CXTransaction, action: String = "") {
callController.request(transaction) { error in
if let error = error {
print("Error requesting transaction: \(error)")
} else {
print("Requested transaction successfully")
}
}
}
public func startCall(){
let activeCall = CometChatCall()
cancelCall = false
activeCall.modalPresentationStyle = .fullScreen
if let window = UIApplication.shared.windows.first , let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentedController = currentController.presentedViewController {
currentController = presentedController
}
currentController.present(activeCall, animated: true, completion: nil)
}
}
}