Hi,
I have implemented VOIP calling feature in my application using OpenTok SDK and CallKit framework. Calling feature is working most of the time. But there is one strange issue I have come across.
During a call, if any external cellular call appears and if I decline that external call then my running voip call also disconnects. This is happening some of the iPhone devices.
iPhone config:
Model: iPhone 11
iOS Version: 17.3
I have added loggers CXEndCallAction and -provider:performEndCallAction and debugged at my end. I found that CXEndCallAction is not executing from my end but still -provider:performEndCallAction is triggered by iOS along with my ongoing callUUID.
This is very strange behaviour I am observing in one of my iPhone device. I have tested this in 4 iPhone devices but i am facing this issue only in 1 iPhone.
Thanks,
CallKit
RSS for tagDisplay the system-calling UI for your app’s VoIP services and coordinate your calling services with other apps and the system using CallKit.
Posts under CallKit tag
78 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi,
I have implemented VOIP calling feature in my application using OpenTok SDK and CallKit framework. Calling feature is working most of the time. But there is one strange issue I have come across.
During a call, if any external cellular call appears and if I decline that external call then my running voip call also disconnects. This is happening some of the iPhone devices.
iPhone config is as follows
Model : iPhone 11
iOS Version : 17.3
I have added loggers CXEndCallAction and -provider:performEndCallAction and debugged at my end . I found that CXEndCallAction is not executing from my end but still -provider:performEndCallAction is triggered by iOS along with my ongoing callUUID
This is very strange behaviour I am observing in one of my iPhone device. I have tested this in around 3-4 iPhone devices but i am facing this issue only in 1 iPhone .
Kindly help me here if anyone has solution around it .
Thanks
My requirement is here-
1- We need to implement functionality in my iOS app to do call (cellular call) without user interaction.
2- We need to implement functionality in my iOS app to send normal message to particular phone number without user interaction.
3- Fetch OS log (NOT MY APPLICATION LOG). we need to fetch OS log when cellular call going on in device this log need to collect in my iOS app for identify the network strength and other things like call is connected and disconnect etc. Thanks
Dear Appple Dev Team,
we have developed an app to identify incoming phone calls via CallKit (https://developer.apple.com/documentation/callkit/cxcalldirectoryextensioncontext). This function works great. However, we are missing a similar function for SMS/iMessage sender identification. Is it possible to integrate this function into iOS.
Thanks
Markus
Hi there! As Developer, wondering if there is a way to distinguish between an actual call and a Live Voicemail?
https://support.apple.com/en-us/105066
Hello,
I would like get advice about the time-sensitive notification ‘interruption-level’ set to ‘time-sensitive’ in the push payload. I’m wondering if this setting applies to VOIP push notifications. I tried to find information in Apple’s documentation, but it doesn’t specify whether it is applicable for VOIP push notifications.
{
"aps": {
"interruption-level": "time-sensitive"
}
}
https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification#:~:text=ContentIdentifier%[…]terruption%2Dlevel,-String
When use callkit, video button in callkit pannel is abnormal. Here are some case:
iOS117 & incoming call: video button disable
iOS17 & outgoing call: video button disable
iOS16 & incoming call: video button enable
iOS16 & outgoing call: video button disable
will appricate for help!
Core code:
private func configureCallKit() {
let configuration = CXProviderConfiguration(localizedName: "CallkitTesting")
configuration.supportsVideo = true // 是否支持视频通话
configuration.supportedHandleTypes = [.generic]
configuration.maximumCallGroups = 1
configuration.maximumCallsPerCallGroup = 1
provider = CXProvider(configuration: configuration)
provider.setDelegate(self, queue: nil)
}
func startOutgoing() {
let handle = CXHandle(type: .generic, value: "!!!!!!")
let startCallAction = CXStartCallAction(call: UUID(), handle: handle)
let transaction = CXTransaction(action: startCallAction)
CXCallController().request(transaction) { error in
if let error = error {
print("Error requesting transaction: \(error.localizedDescription)")
} else {
print("Transaction requested successfully")
}
}
}
Hi Team,
We are facing issues about VOIP call for some users in USA who used the Wi-Fi network of some service provider. They are not receiving the calls on Wi-Fi but able to receive the call when connected to SIM/Data Connection. We implemented the VOIP services of apple and VOIP notification received and call kit UI displayed. Its working fine on public network mostly but not working on some Wi-Fi network in USA.
iPhone 12
Latest iOS version
VOIP notification not received
Call kit not display
App Name=> Owwll
I'm trying to integrate Callkit into a Flutter app that uses webRTC for calls and I have an issue with taking calls on locked screen. CXAnswerCallAction requires to have the action.fulfill() method called after the connection is established. Here is a pice of code without waiting for establishment of the connection:
guard let call = self.callManager?.callWithUUID(uuid: action.callUUID) else{
action.fail()
return
}
call.data.isAccepted = true
self.answerCall = call
self.callManager?.updateCall(call)
sendEvent(SwiftCallKeepPlugin.ACTION_CALL_ACCEPT, call.data.toJSON())
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1200)) {
self.configureAudioSession()
}
action.fulfill()
}
This causes the connection time counter to be immediately visible on the screen, but the user still has to wait for connection establishment and can't hear anything.
Here is the code that waits for the establishment of the connection before calling action.fulfill():
if(self.awaitedConnection.uuid != uuid) {
action.fail()
} else if(self.awaitedConnection.isConnected) {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1200)) {
self.configureAudioSession()
}
action.fulfill()
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000)) {
self.waitForConnection(uuid: uuid, action: action)
}
}
}
public func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
guard let call = self.callManager?.callWithUUID(uuid: action.callUUID) else{
action.fail()
return
}
call.data.isAccepted = true
self.answerCall = call
self.callManager?.updateCall(call)
self.awaitedConnection.uuid = action.callUUID
self.awaitedConnection.isConnected = false
sendEvent(wiftCallKeepPlugin.ACTION_CALL_ACCEPT, call.data.toJSON())
waitForConnection(uuid: action.callUUID, action: action)
}
Unfortunately, though it works great on iOS 15.7, on 17.3 it causes lack of audio, no sound and no recording. I also can't enable it later when the call is ongoing. For reference:
let session = AVAudioSession.sharedInstance()
do{
try session.setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.allowBluetooth)
try session.setMode(self.getAudioSessionMode(data?.audioSessionMode ?? "voiceChat"))
try session.setActive(data?.audioSessionActive ?? true)
try session.setPreferredSampleRate(data?.audioSessionPreferredSampleRate ?? 44100.0)
try session.setPreferredIOBufferDuration(data?.audioSessionPreferredIOBufferDuration ?? 0.005)
}catch{
print(error)
}
}
I can see in the docs of action.fulfill() that "You should only call this method from the implementation of a CXProviderDelegate method". I this the reason for the issue? But how can I do it if I need to wait for the connection asynchronously and the provider method is synchronous?
Hello,
I am developing a service using Voip Push.
Recently, it seems that Voip Push notifications are occasionally arriving late.
Does anyone have information regarding this issue?
Sometimes, when the delay is prolonged, notifications from a few days ago also seem to be received.
Thank you.
Hi. I would like my App to be notified when the phone rings. No, not CallKit-CallKit is for VoIP and does not cover Cellular connections (as of 2/26/24) but, thanks. To continue..
I understand ages-ago there was a Telephony Kit or Framework but, has been discontinued. Has it been replaced with something else?
I would like something that seems very simple:a) when the phone rings my App is notified, b) when it stops ringing (combine all possibilities; sent to voicemail, user cancels, user answers) my App is notified.
Yes, I understand UserNotifications can make things run but, as I understand it this feature is for the App to schedule notifications, not receive them? If you know of something in UserNotifications that I can leverage I would appreciate your input.
Lacking other possibilities I find myself wondering about Siri integration. Siri is notified about system events and generates notifications based upon these events. Is there some way to place my App downstream from Siri and receive system notifications? Thanks everyone.
I have been having a problem in our application while handling the VoIP notifications.
sometimes the didReceiveIncomingPushWith delegate function is invoked when a VoIP Notif is sent but when the call is accepted nothing happened from the caller's side, like the callback to the caller to notify him that the call is accepted doesn't happe.
And sometimes the didReceiveIncomingPushWith is not even invoked when a VoIP notif is sent.
here is a potion of the code.
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
NSLog("pushRegistry didReceiveIncomingPushWith() type:(type)")
// Handle the push payload
if let pushHashtable = payload.dictionaryPayload["aps"] as? [AnyHashable: Any] {
if let pushMessage = pushHashtable["alert"] as? String {
NSLog("push message=\(pushMessage)")
}
}
if type == PKPushType.voIP {
// Process the received push: if it is a VoIP push, this must be an incoming call because we deactivated push for REGISTER refresh from Kamailio server
if SipService.instance?.currentCall != nil {
// A call is already going on, ignore this VoIP push
NSLog("pushRegistry - voip push, and we already have a currentCall: we already received the INVITE, or it is a voip push for another call -> let's ignore it")
completion()
return
}
// We want to send a REGISTER anyway to get the pending INVITE message.
// Then, the incoming call will be notified in the SIP stack onCallNew(_ call: Call!) callback
// Since iOS 13, it is mandatory to report an incoming call immediately after a Voip push
// instead of waiting for the SIP INVITE (in EngineDelegate.onCallNew())
// See details here: https://forums.developer.apple.com/message/376630#376630
NSLog("pushRegistry - >= iOS 13 -> showing callkit before SIP INVITE")
if let callerSipUri = payload.dictionaryPayload["caller-sip-uri"] as? String {
NSLog("push caller-sip-uri=\(String(describing: callerSipUri))")
SipUtils.findCallerName(fromSip: callerSipUri) { callerName in
let customCallerName = (callerName ?? "Inconnu") + (CallKitService.instance?.CALLKIT_DEBUG_MODE == true ? " [PUSH]" : "")
DispatchQueue.main.async {
CallKitService.instance?.reportNewIncomingCallToCallKit(callerName: customCallerName) {
completion()
}
}
}
} else {
// That should not happen: Kamailio server is supposed to add the caller SIP URI in the VoIP push
DispatchQueue.main.async {
CallKitService.instance?.reportNewIncomingCallToCallKit(callerName: nil) {
completion()
}
}
}
// No call is going on, so we want to take this call, so we want to send a REGISTER if needed
SipNetworkMonitoring.instance.start()
} else {
NSLog("pushRegistry - not a VoIP push")
completion()
}
}
here is the reportNewIncomingCallToCallKit function implementation
func reportNewIncomingCallToCallKit(callerName: String?, completion: @escaping () -> Void) {
NSLog("Callkit - reportNewIncomingCallToCallKit from %@", callerName ?? "Inconnu")
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: callerName ?? "Inconnu")
update.hasVideo = true
// we may already have reported a new call to CallKit
// (since iOS13, we must do it in the didReceiveIncomingPushWith() callback)
// In this case, the CallKit UI is already showing with caller="Inconnu": we will update it with the caller name.
if let currentUuid = currentUuid {
NSLog("Callkit - already a CallKit call showing -> updating the existing call ...")
self.cxProvider?.reportCall(with: currentUuid, updated: update)
} else {
NSLog("Callkit - now CallKit call showing -> new call ...")
let newUuid = UUID()
self.currentUuid = newUuid
self.cxProvider?.reportNewIncomingCall(with: newUuid, update: update) { error in
completion()
}
}
// dont configure audioSession here, wait for the Callkit "didActivate audioSession" callback
}
just to clarify : findCallerName is a function to get the called name from a list from the Backend with an escaping closure, (I tried to overpass that function and just give a default name to the caller but still same problem) .
ANY HELP PLEASE?
Hi, We are developing an infotainment system that includes a wireless CarPlay. Can someone confirm the expected behavior when a device connected via wireless car play should do in the below scenario.
iPhone connected through wireless car play and projection is active
in he CarPlay projection a call is going on.
Car play gets disconnected when user switches off the WiFi.
After these steps , should the call only continue on the phone or should the connected get transitioned to HFP ( Hands free profile) and call continue though the head unit in the car.
Do note, WiFi is switched OFF in phone so CarPlay can't restart without user switching it back ON
I have integrated CallKit successfully and I'm trying to handle the video button. In some devices, I get the enabled video button and can request to open a video connection. But for some devices, I get a disabled video icon. What could be the reason for that?
private lazy var provider: CXProvider = {
let configuration = CXProviderConfiguration()
configuration.supportsVideo = true
configuration.maximumCallGroups = 2
configuration.maximumCallsPerCallGroup = 4
configuration.includesCallsInRecents = false
configuration.supportedHandleTypes = [.generic]
return CXProvider(configuration: configuration)
}()
func reportIncomingCall() {
let uuid = UUID()
let update = CXCallUpdate()
update.supportsGrouping = true
update.supportsHolding = true
update.remoteHandle = CXHandle(type: .generic, value: "Name")
update.hasVideo = true // or false
provider.reportNewIncomingCall(with: uuid, update: update) { [weak self] error in
// handle
}
}
Note: Whatsapp has the enabled video button in the same device.
When setting the mode during the configuration of an audio session in Swift, the previously configured categoryOptions get reset. For example, if you perform setMode as shown below, you will observe that all previously set categoryOptions are cleared.
Example:
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .videoChat, options: [.allowBluetooth, .defaultToSpeaker])
try AVAudioSession.sharedInstance().setMode(.voiceChat)
If you need to change the mode while maintaining the categoryOptions, you have to perform setCategory once again. Although the exact reason for this behavior has not been identified, the practical impact on the application's functionality is not yet clear. Why do you think this handling is in place?
I am trying to obtain the phone number of an incoming call or retrieve the last caller's number in my iOS app, but I'm facing challenges. CallKit only seems to provide access to a call's UUID and not the actual phone number. Is there a way to get the caller's phone number using CallKit or any other method in iOS?
Hi! On iOS 16 CallKit for some reason will not ring over 60s.
func reportNewIncomingCall(with UUID: UUID, update: CXCallUpdate, completion: @escaping (Error?) -> Void)
After receiving a VoIP call push, I have reported it as soon as possibile.
Expected result:
Will ring always.
Actual result:
Stop after 60s
When there is an ongoing call, if the user gets another one, we don't want to support multi-call and directly send the new call to the voicemail. For this operation what should be CXCallEndedReason?
My understanding is that remoteEnded is used when the call connected and then ended. unanswered might be the choice for me but would it cause any issue if i directly reject a call with this status (the difference between the incoming call and reject time would be too short)? There is also declinedElsewhere , which might be suitable
I took delivery of my first M1 Mac (iMac running Big Sur 11.4) and with great anticipation installed my iOS VoIP App from the AppStore.
I was greatly disappointed to see that
There were no VoIP Pushes to start an incoming call
Callkit does not seem to work so I get no Audio.
Am I missing something? Is there some permissions or configuration I might need to set?
Or is it just that Callkit and Pushkit don't work even though it states on developer.apple.com that they are supported on macOS 10.15+
Any advice or guidance greatly appreciated.
Very disappointed :-(
i have an issue when handling silent push in my app when the user close the app, here is my native code which works like charm when the app in the foreground, background or terminated status from a short time from closing the app, and after long time from closing it (+30min) it will not work anymore, it make me confuse why it does not work and other messaging app like viber, whatsapp and messanger you can still receive messages and calls even you swipe the app and close it !! is there any thing must i add !!
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
Messaging.messaging().appDidReceiveMessage(userInfo)
if Auth.auth().canHandleNotification(userInfo) {
completionHandler(.noData)
return
}
// sample notification for testing
let content = UNMutableNotificationContent()
content.title = "Hi there"
content.body = "Just test"
content.sound = UNNotificationSound.default
let request = UNNotificationRequest(identifier: "helloNotification", content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print("Error adding notification request: \(error.localizedDescription)")
}
}
// resent to dart side
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let notificationChannel = FlutterMethodChannel(name: "notificationHandler", binaryMessenger: controller.binaryMessenger)
var dataToSend: [String: Any] = [:]
if let text = userInfo["text"] as? String {
dataToSend["text"] = text
}
// Convert the dictionary to NSDictionary
let nsDataToSend = NSDictionary(dictionary: dataToSend)
// Pass the NSDictionary to Dart
notificationChannel.invokeMethod("handleRemoteMessage", arguments: nsDataToSend)
}
i checked :
background capabilities : remote notifs, background fetching, voip, background processing