问题
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.
- 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.
- Given that the
reportNewIncomingCall
is an asynchronous method, you are not guaranteed that thecompletion()
of thepushRegistry(didReceiveIncomingPushWith...)
will be called after the completion of thereportNewIncomingCall
. 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
.
- If
typeCall
is not equal toOPEN_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