CallKit reportNewIncomingCall completion called but still getting “Killing app because it never posted an incoming call …” crash

℡╲_俬逩灬. 提交于 2021-01-07 02:42:58

问题


This is my first time using PushKit and CallKit combination to build a VoIP feature. I noticed that starting from iOS 13 it is mandatory to report a PushKit VoIP push, otherwise the app will crash.

Due to this regulation I proceeded to implement the reportNewIncomingCall method inside didReceiveIncomingPushWith and made sure that its completion is successfully called, which it did, because the breakpoint I placed within the completion block was activated.

However, not long after that, the app crashed and showed "Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP callback", which is weird because previously the completion block was called.

Does anybody know why this happens?

This is the code of reportNewIncomingCall I implemented:

let callUpdate = CXCallUpdate()
callUpdate.remoteHandle = CXHandle(type: .phoneNumber, value: session)
callUpdate.localizedCallerName = username
callUpdate.hasVideo = true
callUpdate.supportsDTMF = false
        
let uuid = {{some uuid}}
        
provider.reportNewIncomingCall(with: uuid, update: callUpdate, completion: { error in
    if let error = error {
         print("reportNewIncomingCall error: \(error.localizedDescription)")
    }
    DispatchQueue.main.async {
        completion()
    }
})

EDIT

This is the pushRegistry(_, didReceiveIncomingPushWith...) code:

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    if type == .voIP {
         guard let payloadData = payload.dictionaryPayload as? [String: Any],
            let data = payloadData["data"] as? [String: Any],
            let typeCall = data["type"] as? String else { completion();return }

         if typeCall == "OPEN_ACTIVITY_CALL" {
              guard let userName = data["userName"] as? String else { completion();return }
              self.appleCallKit?.showIncomingCall(username: userName)
         }
         completion()
    }
}

self.appleCallKit?.showIncomingCall(username: userName) method executes reportNewIncomingCall in the previous code block


回答1:


I think that the problem could be the DispatchQueue.main.async. This will cause your completion handler to be executed later in a future run loop and probably for the system is too late.

Just try to remove it:

provider.reportNewIncomingCall(with: uuid, update: callUpdate, completion: { error in
    if let error = error {
        print("reportNewIncomingCall error: \(error.localizedDescription)")
    }
    completion()
})

EDIT

In the new code you've provided, I can see at least three errors that can lead to the crash.

  1. If one of the guard statements fails, you will not report a new incoming call, hence the app crashes. You should do something like this:
guard let payloadData = payload.dictionaryPayload as? [String: Any],
    let data = payloadData["data"] as? [String: Any],
    let typeCall = data["type"] as? String else { 
        reportFakeCall(completion) // <---
        return 
    }

Report a fake call and immediately terminate it.

  1. Given that the reportNewIncomingCall is an asynchronous method, you are not guaranteed that the completion() of the pushRegistry(didReceiveIncomingPushWith...) will be called after the completion of the reportNewIncomingCall. So, in some cases, the app will crash because you havn't reported a new incoming call before the completion. You should do something like this:
if typeCall == "OPEN_ACTIVITY_CALL" {
    guard let userName = data["userName"] as? String else { 
       reportFakeCall(completion) // <-- As in point 1
       return
    }
    self.appleCallKit?.showIncomingCall(username: userName, completion) // <---
}

Pass the completion handler to the showIncomingCall and call it inside the completion of the reportNewIncomingCall.

  1. If typeCall is not equal to OPEN_ACTIVITY_CALL you don't report a new incoming call and the app crashes.
if typeCall == "OPEN_ACTIVITY_CALL" {
    ...
} else {
    reportFakeCall(completion)
}

You can implement the reportFakeCall method as follows:

func reportFakeCall(completion: @escaping () -> Void)
{
    let callUpdate = CXCallUpdate()
    let vCallId = UUID()
    provider.reportNewIncomingCall(
        with: vCallId,
        update: callUpdate,
        completion: { error in
            completion()
            self.endCall(with: vCallId) // CXEndCallAction transaction
    })
}


来源:https://stackoverflow.com/questions/63481795/callkit-reportnewincomingcall-completion-called-but-still-getting-killing-app-b

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!