flutter_callkit_incoming
flutter_callkit_incoming copied to clipboard
Not working in ios termenated state
If iOS app killed or not in back stack or in terminate state then call kit not working
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:
- Push CallKit from native (didReceiveIncomingPushWith method)
- Connect SIP (Flutter) I use sip_ua package
- 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();
}
});
}
}
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:
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
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 🙂.
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 ?