Open avadhkatrodiya98 opened 1 year ago
iOS app (ver 14.7.1): When app in background/terminated, app stopped.
Apps receving VoIP pushes must post an incoming call (via CallKit or IncomingCallNotifications) in the same run loop as pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay. *** Assertion failure in -[PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes], PKPushRegistry.m:353 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.'
This happens for us too across all iOS versions we have tested so far with flutter sdk v3.7.0 and flutter_callkit_incoming v1.0.3+3.
This happens for us too across all iOS versions we have tested so far with flutter sdk v3.7.0 and flutter_callkit_incoming v1.0.3+3.
Hi bro, You can fix the error in the following way:
In native (Swift)
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
print("Call answer from CallKit")
flutterMethodChannel?.invokeMethod("acceptCall", arguments: "")
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
print("Call ended from CallKit")
flutterMethodChannel?.invokeMethod("declineCall", arguments: "")
action.fulfill()
}
In Flutter:
const pushCallKitChannel = IosMethodChannel.pushCallKitChannel;
if (callState.state == CallStateEnum.CALL_INITIATION) {
if (Platform.isIOS) {
pushCallKitChannel.setMethodCallHandler((handler) async {
if (handler.method == 'acceptCall') {
handleAccept();
OneContext().push(
MaterialPageRoute(
builder: (context) => CallingScreen(helper, call),
),
);
}
if (handler.method == 'declineCall') {
handleHangup();
}
});
}
}
Thank for your reply we implement it and test it
On Mon, Apr 24, 2023 at 8:11 AM tinhnvc-gadget @.***> wrote:
This happens for us too across all iOS versions we have tested so far with flutter sdk v3.7.0 and flutter_callkit_incoming v1.0.3+3.
Hi bro, You can fix the error in the following way:
1.
Push CallKit from native (didReceiveIncomingPushWith method) 2.
Connect SIP (Flutter) I use sip_ua package 3.
In CXAnswerCallAction and CXEndCallAction invoke Flutter In native (Swift) ` func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { print("Call answer from CallKit") flutterMethodChannel?.invokeMethod("acceptCall", arguments: "") action.fulfill() }
func provider(_ provider: CXProvider, perform action: CXEndCallAction) { print("Call ended from CallKit") flutterMethodChannel?.invokeMethod("declineCall", arguments: "") action.fulfill() }In Flutter: const pushCallKitChannel = IosMethodChannel.pushCallKitChannel;
if (callState.state == CallStateEnum.CALL_INITIATION) { if (Platform.isIOS) { pushCallKitChannel.setMethodCallHandler((handler) async { if (handler.method == 'acceptCall') { handleAccept(); OneContext().push( MaterialPageRoute( builder: (context) => CallingScreen(helper, call), ), ); }
if (handler.method == 'declineCall') { handleHangup(); } });
} }`
— Reply to this email directly, view it on GitHub https://github.com/hiennguyen92/flutter_callkit_incoming/issues/270#issuecomment-1519300636, or unsubscribe https://github.com/notifications/unsubscribe-auth/A5JLYR2J7JUC7IB3HNIAWF3XCXR6XANCNFSM6AAAAAAW3GN27A . You are receiving this because you authored the thread.Message ID: @.***>
Hello @avadhkatrodiya98, the solution provide by @tinhnvc-gadget worked for you? Can you provide more detail about how can be implemented? Please!
iOS app (ver 14.7.1): When app in background/terminated, app stopped.
Apps receving VoIP pushes must post an incoming call (via CallKit or IncomingCallNotifications) in the same run loop as pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay. *** Assertion failure in -[PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes], PKPushRegistry.m:353 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.'
I have the same issue in flutter_callkit_incoming version 2.0.0. @hiennguyen92
I found a solution. In some cases, you don't want to show pushKit from VoIP such as rejected calls.
ref: https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry
I use SwiftFlutterCallkitIncomingPlugin.sharedInstance.showCallkitIncoming to report incoming calls completion to block and let PushKit know you are finished.
this code from my case
// Handle incoming pushes
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
print("didReceiveIncomingPushWith")
guard type == .voIP else { return completion() }
let uuid = UUID().uuidString
let id = payload.dictionaryPayload["id"] as? String ?? uuid
let nameCaller = payload.dictionaryPayload["name"] as? String ?? ""
let action = payload.dictionaryPayload["action"] as? String ?? ""
var info = [String: Any?]()
info["id"] = id
info["nameCaller"] = nameCaller
info["handle"] = "generic" // phoneNum/email/generic
info["type"] = 0 //isVideo set 1. not video set 0
info["platform"] = "ios"
info["duration"] = 60000
info["supportsVideo"] = true
info["maximumCallGroups"] = 1
info["maximumCallsPerCallGroup"] = 1
info["audioSessionMode"] = "default"
info["audioSessionActive"] = true
info["audioSessionPreferredSampleRate"] = 44100.0
info["audioSessionPreferredIOBufferDuration"] = 0.005
info["supportsDTMF"] = false
info["supportsHolding"] = false
info["supportsGrouping"] = false
info["supportsUngrouping"] = false
info["ringtonePath"] = "system_ringtone_default"
let data = flutter_callkit_incoming.Data(args: info)
//data.iconName = ...
//data.....
let appState = getAppState()
let notificationData = payload.dictionaryPayload
notificationData["id"] = id
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "method_channel", binaryMessenger: controller.binaryMessenger)
let args: [String: Any] = [
"notificationData": notificationData,
"appState":"\(appState)"
]
channel.invokeMethod("CALLING", arguments: args)
SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true)
completion();
}
// Get App state
enum AppState {
case active
case background
case inactive
case terminated
case unknown
}
// Get App state
func getAppState() -> AppState {
if UIApplication.shared.responds(to: #selector(getter: UIApplication.shared.backgroundRefreshStatus)) {
// Check if the app is being terminated due to a system shutdown
if UIApplication.shared.backgroundRefreshStatus == .denied && UIApplication.shared.applicationState == .background {
return .terminated
}
}
switch UIApplication.shared.applicationState {
case .active:
return .active
case .background:
return .background
case .inactive:
return .inactive
@unknown default:
return .unknown
}
}
I hope this solution will help you 🙂.
I found a solution. In some cases, you don't want to show pushKit from VoIP such as rejected calls.
ref: https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry
completion()
- The notification's completion handler. Execute this block when you finish processing the notification.
I use SwiftFlutterCallkitIncomingPlugin.sharedInstance.showCallkitIncoming to report incoming calls completion to block and let PushKit know you are finished.
this code from my case
// Handle incoming pushes func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { print("didReceiveIncomingPushWith") guard type == .voIP else { return completion() } let uuid = UUID().uuidString let id = payload.dictionaryPayload["id"] as? String ?? uuid let nameCaller = payload.dictionaryPayload["name"] as? String ?? "" let action = payload.dictionaryPayload["action"] as? String ?? "" var info = [String: Any?]() info["id"] = id info["nameCaller"] = nameCaller info["handle"] = "generic" // phoneNum/email/generic info["type"] = 0 //isVideo set 1. not video set 0 info["platform"] = "ios" info["duration"] = 60000 info["supportsVideo"] = true info["maximumCallGroups"] = 1 info["maximumCallsPerCallGroup"] = 1 info["audioSessionMode"] = "default" info["audioSessionActive"] = true info["audioSessionPreferredSampleRate"] = 44100.0 info["audioSessionPreferredIOBufferDuration"] = 0.005 info["supportsDTMF"] = false info["supportsHolding"] = false info["supportsGrouping"] = false info["supportsUngrouping"] = false info["ringtonePath"] = "system_ringtone_default" let data = flutter_callkit_incoming.Data(args: info) //data.iconName = ... //data..... let appState = getAppState() let notificationData = payload.dictionaryPayload notificationData["id"] = id let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let channel = FlutterMethodChannel(name: "method_channel", binaryMessenger: controller.binaryMessenger) let args: [String: Any] = [ "notificationData": notificationData, "appState":"\(appState)" ] channel.invokeMethod("CALLING", arguments: args) SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true) completion(); }
// Get App state enum AppState { case active case background case inactive case terminated case unknown } // Get App state func getAppState() -> AppState { if UIApplication.shared.responds(to: #selector(getter: UIApplication.shared.backgroundRefreshStatus)) { // Check if the app is being terminated due to a system shutdown if UIApplication.shared.backgroundRefreshStatus == .denied && UIApplication.shared.applicationState == .background { return .terminated } } switch UIApplication.shared.applicationState { case .active: return .active case .background: return .background case .inactive: return .inactive @unknown default: return .unknown } }
I hope this solution will help you 🙂.
The solution didn't work for me. The app would still crash on iOS after ending the call with log saying the call wasn't reported callkit.
I also have a issue open here already. https://github.com/hiennguyen92/flutter_callkit_incoming/issues/197
sorry this happened. you may need to add this after showIncoming. https://github.com/hiennguyen92/flutter_callkit_incoming/blob/6cb1ba422f835fc2482cb5c012cba1ecdb237188/example/ios/Runner/AppDelegate.swift#L78
for sure you can add this
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { completion() }
Can you please share a solution for rejecting a call from an incoming call(talker) before accepting a call via pushKit? @hiennguyen92
Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.
@hiennguyen92 thanks you but unfortunately calling completion() did not fix it. I still get "Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback." error and the app crashes
Stuck with same issue? any update on this issue? . I am using ^1.0.3+3 version
Stuck with same issue? any update on this issue? flutter_callkit_incoming: ^2.0.4
Stuck with same issue? any update on this issue? flutter_callkit_incoming: ^2.0.4+1
Stuck with the same issue any updates ?
If iOS app killed or not in back stack or in terminate state then call kit not working