问题描述
这是我第一次使用PushKit
和CallKit
组合来构建VoIP功能。我注意到,从iOS 13开始,必须报告 PushKit VoIP推送,否则该应用将崩溃。
由于这项规定,我继续在reportNewIncomingCall
内实现didReceiveIncomingPushWith
方法,并确保成功完成了它的完成,因为我放置在完成块中的断点已被激活。
但是,此后不久,该应用程序崩溃并显示“杀死应用程序,因为它在收到PushKit VoIP回调后从未向系统发布来话呼叫”,这很奇怪,因为之前已调用完成模块。
有人知道为什么会这样吗?
这是我实现的reportNewIncomingCall
的代码:
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()
}
})
编辑
这是pushRegistry(_,didReceiveIncomingPushWith...)
代码:
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)
方法在上一个代码块中执行reportNewIncomingCall
解决方法
我认为问题可能出在DispatchQueue.main.async
上。这将使您的completion
处理程序在以后的运行循环中稍后执行,可能对系统而言为时已晚。
只需尝试将其删除:
provider.reportNewIncomingCall(with: uuid,update: callUpdate,completion: { error in
if let error = error {
print("reportNewIncomingCall error: \(error.localizedDescription)")
}
completion()
})
编辑
在您提供的新代码中,我至少看到了三个可能导致崩溃的错误。
- 如果
guard
语句之一失败,则不会报告新的来电,因此应用程序崩溃。您应该执行以下操作:
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
}
举报虚假电话并立即终止。
- 鉴于
reportNewIncomingCall
是异步方法,因此不能保证completion()
完成后将调用pushRegistry(didReceiveIncomingPushWith...)
的{{1}}。因此,在某些情况下,该应用程序将崩溃,因为您在完成之前没有报告新的来电。您应该执行以下操作:
reportNewIncomingCall
将完成处理程序传递给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) // <---
}
,并在showIncomingCall
的完成内调用它。
- 如果
reportNewIncomingCall
不等于typeCall
,则不会报告新的来电,并且应用会崩溃。
OPEN_ACTIVITY_CALL
您可以如下实现if typeCall == "OPEN_ACTIVITY_CALL" {
...
} else {
reportFakeCall(completion)
}
方法:
reportFakeCall