Display 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

112 Posts

Post

Replies

Boosts

Views

Activity

Error Blocking Phone Numbers
In my case, when I try to block calls on iOS 26, the blocking doesn't occur; the scenarios seem intermittent. If I create two CallDirectory extensions, the first blocks the numbers, but the second doesn't. Interestingly, the extension marks the number as suspicious. There's also a case where, on iOS 26 on an iPhone 16 Pro, the functionality doesn't work at all. I'd like to know if there have been any changes to the use of CallKit in iOS 26, because users of my app on iOS 18 and below report successful blocking.
1
1
324
Dec ’25
Call log
I read online that there is no way to extract the call log from an iPhone. I want to develop an app to help people remember to call their mom, and if they did, the "nagging" would disappear automatically. I'm looking for any workaround to know when a user called someone, without having them log it manually.
1
0
481
Dec ’25
CallKit VoIP → App launch → Auto WebRTC/MobileRTC connection: Does Apple allow this flow?
Our app receives a CallKit VoIP call. When the user taps “Answer”, the app launches and automatically connects to a real-time audio session using WebRTC or MobileRTC. We would like to confirm whether the following flow (“CallKit Answer → app opens → automatic WebRTC or MobileRTC audio session connection”) complies with Apple’s VoIP Push / CallKit policy. In addition, our service also provides real-time video-class functionality using the Zoom Meeting SDK (MobileRTC). When an incoming CallKit VoIP call is answered, the app launches and the user is automatically taken to the Zoom-based video lesson flow: the app opens → the user is landed on the Zoom Meeting pre-meeting room → MobileRTC initializes immediately. In the pre-meeting room, audio and video streams can already be active and MobileRTC establishes a connection, but the actual meeting screen is not joined until the user explicitly taps “Join”. We would like to confirm whether this flow for video lessons (“CallKit Answer → app opens → pre-meeting room (audio/video active) → user taps ‘Join’ → enter actual meeting”) is also compliant with Apple’s VoIP Push and CallKit policy.
1
0
166
Dec ’25
Are notification pushes not being received when in Picture-in-Picture mode?
Hello, I recently had an unusual experience, and I’m wondering if this is related to Apple’s policies, so I wanted to ask. While a call is in Picture-in-Picture (PIP) mode, notification pushes from the same app do not appear. The API is being triggered, but the notification banner does not show on the device. Once PIP is closed, the notifications start appearing normally again. Is this behavior enforced by Apple’s policies? What’s interesting is that banners from other apps do appear — only the banners from the app currently in PIP are not shown.
1
0
299
Dec ’25
CallKit issue
In iOS 26.1, after my app answers a VoIP call on the lock screen, tapping the bottom-left "More" button doesn't bring up the app icon to jump to the app. The same scenario works normally on iOS 26. How can I resolve this issue?
1
1
158
Dec ’25
VoIP Push Notifications Not Delivered in Background/Killed State (Using AppDelegate)
Hello, colleagues. I am reaching out to the community with an issue that is likely quite common. Unfortunately, I have not been able to resolve it independently and would like to confirm if my approach is correct. Core Problem: VoIP push notifications are not delivered to the application when it is in the background or terminated. After reviewing existing discussions on the forum, I concluded that the cause might be related to CallKit not having enough time to register. However, in my case, I am using AppDelegate, and in theory, CallKit registration should occur quickly enough. Nevertheless, the issue persists. Additional Question: I would also like to clarify the possibility of customizing the CallKit interface. Specifically, I am interested in adding custom buttons (for example, to open a door). Please advise if such functionality is supported by CallKit itself, or if a different approach is required for its implementation. Thank you in advance for your time and attention to my questions. For a more detailed analysis, I have attached a fragment of my code below. I hope this will help clarify the situation. Main File @main struct smartappApp: App { @UIApplicationDelegateAdaptor private var delegate: AppDelegate @StateObject private var navigationManager = NavigationManager() init() { print("Xct") if !isRunningTests() { DILocator.instance .registerModules([ ConfigModule(), SipModule(), AuthModule(), NetworkModule(), CoreDataModule(), RepositoryModule(), DataUseCaseModule(), SipUseCaseModule() ]) } } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("Axtest") completionHandler(.newData) } var body: some Scene { App Delegate File class AppDelegate: UIResponder, UIApplicationDelegate { private let voipRegistry = PKPushRegistry(queue: .main) private var provider: CXProvider? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { setupPushKit() setupCallKit() return true } public func regist(){ setupPushKit() setupCallKit() } private func setupPushKit() { voipRegistry.delegate = self voipRegistry.desiredPushTypes = [.voIP] DispatchQueue.main.async { self.voipRegistry.pushToken(for: .voIP) } } // MARK: - CallKit Setup private func setupCallKit() { let configuration = CXProviderConfiguration(localizedName: "MyApp") configuration.maximumCallGroups = 1 configuration.maximumCallsPerCallGroup = 1 configuration.supportsVideo = true configuration.iconTemplateImageData = UIImage(named: "callIcon")?.pngData() provider = CXProvider(configuration: configuration) provider?.setDelegate(self, queue: .main) } // MARK: - Background Launch Handling func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("Axtest") completionHandler(.newData) } } extension AppDelegate: PKPushRegistryDelegate { func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) { APNsImpl().registerToken(token: pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()) } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) { guard type == .voIP else { return } print("call kit") let payloadDict = payload.dictionaryPayload let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .phoneNumber, value: "dsfsdfddsf") update.hasVideo = payloadDict["hasVideo"] as? Bool ?? false provider?.reportNewIncomingCall(with: UUID(), update: update, completion: { error in if let error = error { print("Failed to report incoming call: \(error.localizedDescription)") } else { print("Successfully reported incoming call") } }) } }
1
0
273
Dec ’25
Critical CallKit Issue: Audio Route Flapping due to reason: 3 (CategoryChange) after User Toggle
I am facing a severe audio routing instability issue when using CallKit and the Zego Express SDK on iOS. The problem is that the audio route immediately reverts from the Speaker back to the Earpiece, effectively disabling the Speaker button functionality.📝 Observed BehaviorWhen the user taps the native CallKit Speaker Button, the audio route is correctly changed to the Speaker, but then instantly flips back to the Receiver (Earpiece), as shown in the system log captured via AVAudioSession.routeChangeNotification monitoring.🧾 Log Evidence (Flapping Occurs in 0.4 seconds)The following log snippet clearly illustrates the system overriding the user's action (reason: 4) with an unexpected CategoryChange (reason: 3) event: TimestampComponentReason CodeDescriptionRouteIs Speaker16:31:18.009[CallKitManager]4Override (CallKit/ControlCenter)Loa ngoài (Speaker)true16:31:18.411[CallKitManager]3CategoryChangeThiết bị nhận (Receiver)false
1
0
351
Dec ’25
iOS 26: Unable to Transition from CallKit Screen to App when remoteHandle is nil or empty string
Hello, I am developing an internal phone application using CallKit. I am experiencing an issue with the behavior of remoteHandle settings in iOS 26 and would appreciate any insights you can provide towards a solution. 1. Problem Description When an iPhone running iOS 26 is in a sleep state and receives a VoIP incoming call where remoteHandle is set to nil or an empty string (@""), we are unable to transition to our application (the UIExtension provided by the provider) from the CallKit UI's "More" (…) button after answering the call. 2. Conditions and Symptoms OS Version: iOS 26 Initial State: iPhone is in a sleep state Call Type: An unsolicited(unknown number) VoIP incoming call where the CXCallUpdate's remoteHandle is set to either nil or [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:@""] Symptoms: After answering the VoIP call by sliding the button, selecting the "More" (…) button displayed on the CallKit screen does not launch our application's UIExtension (custom UI), and the iPhone instead stay to the CallKit screen. 3. Previous Behavior (Up to iOS 18) Up to iOS 18, even when remoteHandle was set to an empty string using the following code, the application would transition normally from "More" after answering an incoming call from a sleep state. CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:@""]; [provider reportNewIncomingCallWithUUID:uuid update:update completion:completion]; 4. Unsuccessful Attempts to Resolve The issue remained unresolved after changing the handling for unsolicited(unknown number) incoming calls as follows: CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = nil; // Set remoteHandle to nil [provider reportNewIncomingCallWithUUID:uuid update:update completion:completion]; 5. Workaround (Temporary) The problem can be resolved, and the application can transition successfully, by setting a dummy numerical value (e.g., "0") for the value in remoteHandle using the following code: CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:@"0"]; // Set a dummy numerical value [provider reportNewIncomingCallWithUUID:uuid update:update completion:completion]; 6. Additional Information If remoteHandle is correctly set with the caller's number (i.e., not an unsolicited(unknown number) call; e.g., value:@"1234567890"), the application transitions normally from the "More" button after answering an incoming call from a sleep state, even in iOS 26. The above issue does not occur when answering incoming calls while the iPhone is in an active state (not sleeping). 7. Questions Have there been any other reports of similar behavior? Should this be considered a bug in CallKit for iOS 26? Should I make file a new Feedback report? Is there a suitable method to resolve this issue when the caller ID is unsolicited (nil or an empty string)? This problem significantly impacts user operations as end-users are unable to perform essential in-app actions such as hold or transfer after answering an unsolicited(unknown number) call from a sleep state. We are eager to find an urgent solution and would appreciate any information or advice you can provide. Thank you for your assistance.
5
0
657
Feb ’26
Is there a way to prevent the app from coming to the foreground when accepting a call with a banner-type call kit in a VoIP app?
I'm developing a VoIP app. Currently, I'm using CallKit to control call acceptance, and end-of-call processing. When a call comes in while using the phone, CallKit appears as a banner at the top of the screen. When I click "Accept" on the banner, the app opens and the call is received. (For OEMs, clicking the "Accept" button in the banner will accept the call as is.) The reason this feature is needed is, for example, when a call comes in as a banner call while using a navigation app, accepting the call causes the navigation app to go to the back and the VoIP app to come to the foreground, causing inconvenience to customers. This needs to be improved. Please advise.
1
0
144
Dec ’25
CXCallDirectoryProvider – Numbers added but blocking not working
Hi all, I'm working on a Call Directory Extension using CXCallDirectoryExtensionContext. I want to add a list of numbers to be blocked. Here's the function I use: override func beginRequest(with context: CXCallDirectoryExtensionContext) { context.delegate = self let blockedNumbers = loadNumberEntries(forKey: blockedKey) let identifiedNumbers = loadNumberEntries(forKey: identifiedKey) addAllBlocking(blockedNumbers, to: context) addAllIdentification(identifiedNumbers, to: context) context.completeRequest() } private func addAllBlocking(_ entries: [NumberEntry], to context: CXCallDirectoryExtensionContext) { let numbers: [Int64] = entries.compactMap { Int64($0.countryCode + $0.phone) }.sorted() for number in numbers { context.addBlockingEntry(withNextSequentialPhoneNumber: number) print("# Added blocking entry: \(number)") } } When I run this, I see in the console: # Added blocking entry: (*my number with country code*) So it seems the number is added correctly. However, in practice, the number is not blocked on the device. I’ve made sure that: The number is stored with the country code prefix. The extension is enabled in Settings → Phone → Call Blocking & Identification. The extension is reloaded after adding numbers. The array of numbers is sorted in ascending order before calling addBlockingEntry. Despite all this, the number still isn’t blocked. Does anyone know why the print shows the number added, but it doesn’t actually block the call? Am I missing something in the way CXCallDirectoryExtensionContext works? Thanks for any advice!
1
0
957
Jan ’26
CallKit automatically shows a system top toast after iOS 26, how to dismiss it?
I’m developing an iOS app that integrates with CallKit. Starting from iOS 26, I’ve noticed that the system automatically presents a top banner / toast-style UI when a CallKit call becomes active (see attached screenshot). This UI appears to be fully managed by the system. On iOS versions prior to iOS 26, this UI did not appear under the same CallKit configuration. What I’ve observed The banner is displayed automatically by the system It appears at the top of the screen, similar to a toast or call status banner It is not a view created by my app I could not find any public API or CallKit configuration related to dismissing or controlling it My questions: Is this top banner an intended system behavior change in newer iOS versions? Is there any public API to dismiss, hide, or customize this UI? If not, is this UI considered non-dismissible by design? Any clarification on the expected behavior or recommended approach would be greatly appreciated.
Topic: UI Frameworks SubTopic: UIKit Tags:
4
0
488
Apr ’26
long wait time for usernotifications.filtering entitlement
Hi, happy new year, I'm a Product Manager for a communications app that's currently in testflight. We requested the com.apple.developer.usernotifications.filtering entitlement on December 3rd, and have yet to receive a response from Apple. I understand that the holiday break may have gotten in the way, however it feels like we were lost in the queue as it's been 6 weeks with no response. Our app owner has checked-in inside appstoreconnect but has not received anything back. Is this common? Is there any process for getting a status update? Are we doing something wrong? Without this entitlement we cannot make the device ring in the background. The app is a voice and video messaging platform.
1
2
502
Jan ’26
What are the image requirements for the logo for Live Caller ID?
When Live Caller ID first came out I experimented with it and got it working using the Example PIR database. All my links from that time are now out of date and no longer work, however I seem to have found where the PIR database example and documentation has moved to (https://swiftpackageindex.com/apple/pir-service-example/main/documentation/pirservice/testinginstructionslivecalleridlookup) But what I can't find is an exact definition of the the logo size/max size/dimensions/format should be. My memory from that time is that it was very pernickety, and if things weren't exactly right, the logo wasn't displayed. I can remember the format had to be HEIC to get it to work. Looking through the documentation however, I can't see exact requirements specified. My question is - for the Live Caller ID logo what are the exact image requirements, and where are they documented?
0
0
217
Feb ’26
About audio playback panel after call end.
Dear Apple Support Team, Thank you for your continued support. I would like to inquire about the behavior of CallKit. Our company provides an office PBX extension phone application (iPhone app). When the iPhone is placed into sleep mode (screen off) and our app receives an incoming call, the following sequence sometimes results in an audio playback panel appearing at the bottom of the lock screen for a few seconds after the call ends(See attachment file for detail). Sequence to reproduce the issue: Put the iPhone into sleep mode (screen off). Receive an incoming call to our extension phone app. CallKit incoming call screen appears. Answer the call. Conduct the call. End the call from the peer. iOS versions with confirmed behavior: iOS 26.0: Not observed. iOS 26.2: Observed. iOS 26.3: Not observed. This behavior does not affect the call functionality itself; however, some users report that the temporary appearance of the audio playback panel feels unusual. If there is any known reason for this behavior or any recommended workaround, we would greatly appreciate your guidance. Additionally, if this is a known issue that was addressed in iOS 26.3, we would appreciate any information you can provide regarding that as well. Thank you very much for your assistance.
2
0
255
Feb ’26
New PushKit delegate in iOS 26.4
Starting in iOS 26.4, PushKit has introduced a new "didReceiveIncomingVoIPPushWithPayload" delegate, making it explicit whether or not an app is required to report a call for any given push. The new delegate passes in a PKVoIPPushMetadata object which includes a "mustReport" property. We have not documented the exact criteria that will cause a mustReport to return false, but those criteria currently include: The app being in the foreground at the point the push is received. The app being on an active call at the point the push is received. The system determines that delivery delays have made the call old enough that it may no longer be viable. When mustReport is false, apps should call the PushKit completion handler (as they previously have) but are otherwise not required to take any other action. __ Kevin Elliott DTS Engineer, CoreOS/Hardware
0
0
407
Feb ’26
iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call
iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call Description I have successfully implemented VoIP pushes for the Killed state, where CallKit triggers correctly. However, when the app is in the Background state (suspended), it consistently crashes with an NSInternalInconsistencyException. The app process is killed by the iOS Watchdog because it fails to satisfy the requirement of posting an incoming call in the same run loop as the push receipt, or the completion handler is not being released fast enough by the JS bridge. Environment React Native Version: .78 React Native CallKeep Version: 4.3.14 React Native VoIP Push Notification Version: 3.3.3 iOS Version: 18.x Device: Physical iPhone [iphone 13 pro] The Issue When a VoIP push arrives while the app is in the Background: pushRegistry:didReceiveIncomingPushWithPayload: is called. RNCallKeep.reportNewIncomingCall is triggered on the Main Thread. The app is terminated by the system before the CallKit UI is fully established or before the completion() closure is executed. Current Implementation (AppDelegate.swift) func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { let payloadDict = payload.dictionaryPayload let callerName = payloadDict["callerName"] as? String ?? "Unknown Caller" let callUUIDString = payloadDict["uuid"] as? String ?? UUID().uuidString let userGUID = payloadDict["guid"] as? String ?? "0" RNCallKeep.reportNewIncomingCall( callUUIDString, handle: userGUID, handleType: "generic", hasVideo: false, localizedCallerName: callerName, supportsHolding: true, supportsDTMF: true, supportsGrouping: true, supportsUngrouping: true, fromPushKit: true, payload: ["userGuid": userGUID], withCompletionHandler: { } ) RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue) completion() } Logs Exception Type: EXC_CRASH (SIGKILL) Exception Note: EXC_CORPSE_NOTIFY Termination Reason: TCC 1 | [CoreFoundation] Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push. Observed Behavior Killed State: Works perfectly. Foreground State: Works perfectly. Background State: The phone may vibrate once, but the app process is killed before the CallKit UI appears. Questions/Suspected Causes Is RNVoipPushNotificationManager.addCompletionHandler causing a delay in the background run loop that triggers the Watchdog? Should completion() be called immediately in Swift for the Background state, rather than waiting for VoipPushNotification.onVoipNotificationCompleted in JS? Is there a known issue with RNCallKeep not being able to present the UI while the app is in a suspended background state?
3
0
315
Feb ’26
Frequent providerDidReset Callbacks in Production
Hello, We're seeing a high rate of providerDidReset callbacks in production across a large user base (iOS 16, 17, 18, and 26). I'd like to understand both the correct way to handle this delegate method and strategies to reduce its frequency. Background The callback occurs across all iOS versions we support and is not isolated to a specific device or region. The callback can occur in any app state (foreground, background, inactive), however it is most dominant in the background state — particularly during VoIP push notification handling. The callback is more prevalent during long app sessions — for example, when the app has been running continuously for a day or overnight. We do not call CXProvider.invalidate() anywhere in our codebase explicitly. After providerDidReset fires, subsequent transactions fail with CXErrorCodeRequestTransactionErrorUnknownCallUUID (error code 4). Re-initializing the provider via initializeProvider() resolves this error. Our Implementation We use a singleton proxy class (CallKitProxy) that owns the CXProvider. Below is a simplified version — some logging and non-essential parts have been removed for brevity. @objcMembers public final class CallKitProxy: NSObject { private var cxProvider: CXProvider? private let cxCallController: CXCallController private let cxCallObserver: CXCallObserver private override init() { cxCallObserver = CXCallObserver() cxCallController = CXCallController() super.init() initializeProvider() cxCallObserver.setDelegate(self, queue: nil) } private func initializeProvider() { let configuration = providerConfiguration() cxProvider = CXProvider(configuration: configuration) cxProvider?.setDelegate(self, queue: nil) } private func providerConfiguration() -> CXProviderConfiguration { let soundName = SharedUDHelper.shared.string(forKey: .pushNotificationSoundNameForCall) let sound = CallNotificationSounds(name: soundName ?? "ringtoneDefault") let configuration = CXProviderConfiguration() configuration.supportsVideo = true configuration.maximumCallsPerCallGroup = 1 configuration.maximumCallGroups = 1 configuration.supportedHandleTypes = [.phoneNumber, .generic] configuration.iconTemplateImageData = UIImage( named: "callkit_mask", in: .main, compatibleWith: nil )?.pngData() configuration.ringtoneSound = sound.name return configuration } public func requestTransaction( action: CXCallAction, completion: @escaping (Error?) -> Void ) { let transaction = CXTransaction(action: action) cxCallController.request(transaction) { error in completion(error) } } } extension CallKitProxy: CXProviderDelegate { public func providerDidReset(_ provider: CXProvider) { // End any active calls, then re-initialize the provider initializeProvider() } } Questions 1. Is re-initializing the provider inside providerDidReset the correct approach? The documentation states that providerDidReset signals the provider has been reset and all calls should be considered terminated. Should we be calling CXProvider.invalidate() on the old instance before creating a new one? Or is assigning a new CXProvider to cxProvider (which releases the old instance) sufficient? 2. What could be causing providerDidReset to fire so frequently, and how can we reduce it? We're particularly concerned about cases triggered during VoIP push handling in the background and inactive states. Are there known conditions — such as provider configuration changes, app lifecycle events, or system memory pressure — that commonly trigger this callback? And are there any recommended patterns to make the provider more resilient in these scenarios? Thank you.
1
0
287
Mar ’26
Live Caller ID Lookup: does iOS call /queries even when the number is in Contacts?
Hi! We’ve had Live Caller ID Lookup in production for a while. We’re seeing backend RPS on our /queries endpoint much higher than our expected incoming call volume. While testing with Console.app during an incoming call, it looks like iOS may still hit our service even when the caller number is already in the user’s Contacts - but I’m not 100% sure from logs alone. Can you confirm: Does iOS invoke Live Caller ID Lookup (i.e. call /queries) for every incoming call, including calls from saved Contacts? If yes, is this simply expected framework behavior? Thanks!
0
0
314
Mar ’26
Questions about VoIP Push compliance rules and CallKit handling
Hello everyone, I’m an iOS developer working on a real-time communication app that supports VoIP calls using CallKit. The app has been in production for more than 5 years. Over the years, some users have occasionally reported that they do not receive incoming call pushes. We have tried multiple optimizations on both the client and server side, but the improvement has been limited. From Apple documentation and discussions online, I understand that iOS may restrict VoIP pushes if the system detects violations of VoIP push usage rules (for example, not presenting a CallKit call after receiving a VoIP push). However, the exact rules and thresholds for these violations are not clearly documented, so I’d like to ask a few questions to better understand the expected behavior. Below is a simplified description of our current call flow. Call Flow Caller When the user initiates a call: We do not use CallKit The call is handled entirely using a custom in-app call UI Callee When the user receives a call: Device locked or app in background A VoIP push wakes the app The app presents the CallKit incoming call UI App in foreground The server still sends a VoIP push The app first reports the call to CallKit After a very short delay, the app programmatically ends the CallKit call Then a custom in-app call UI is presented via the app's long connection The reason we always send a VoIP push (even when the app is in the foreground) is that we want to maximize call delivery reliability.
5
0
471
Mar ’26
Clarification on Allowed Uses of VoIP Push Notifications for Ending/Updating CallKit State
Hello, I’m implementing VoIP calling in an iOS application using PushKit (VoIP pushes) together with CallKit. The standard call flow works correctly: Happy scenario User A initiates a call. Server sends a VoIP push to User B. User B’s device receives the push and reports the incoming call using CallKit. User B answers the call. However, I would like clarification about non-happy scenarios and when it is acceptable to use VoIP pushes to update or stop a CallKit ringing state. Apple documentation warns that VoIP pushes must be used only when they result in a call-related action, so I want to ensure the following cases are compliant. Scenario A — Caller Cancels Before Answer User A calls User B. Server sends a VoIP push to User B. User B’s device starts ringing via CallKit. Before User B answers, User A cancels the call. Question: Is it acceptable to send another VoIP push to User B indicating that the call has been cancelled so the device can: stop the CallKit ringing UI end the call optionally mark it as missed or cancelled Or should this state change be handled using a regular remote push or another signaling mechanism instead of VoIP push? Scenario B — Callee Rejects the Call User B rejects the call from CallKit. The server must inform User A that the call was rejected. Question: Is it acceptable to send a VoIP push to User A to update the CallKit state and terminate the outgoing call UI? Scenario C — Multiple Devices per User User B may be logged in on multiple devices. User A calls User B. VoIP push is sent to all devices of User B. One device answers. Question: Is it acceptable to send a VoIP push to the remaining devices instructing them to: stop ringing end the CallKit incoming call UI Or is there a recommended alternative pattern for this case? Main Question Aside from the initial incoming call VoIP push, in which situations is it considered acceptable to send additional VoIP pushes to terminate or update CallKit state (cancelled, rejected, answered on another device)? The goal is to remain compliant with PushKit policies, particularly the guidance that VoIP pushes should only be used when they result in a call-related user action. Any guidance on the recommended architecture for these cases would be greatly appreciated. Thank you.
1
0
328
Mar ’26
Error Blocking Phone Numbers
In my case, when I try to block calls on iOS 26, the blocking doesn't occur; the scenarios seem intermittent. If I create two CallDirectory extensions, the first blocks the numbers, but the second doesn't. Interestingly, the extension marks the number as suspicious. There's also a case where, on iOS 26 on an iPhone 16 Pro, the functionality doesn't work at all. I'd like to know if there have been any changes to the use of CallKit in iOS 26, because users of my app on iOS 18 and below report successful blocking.
Replies
1
Boosts
1
Views
324
Activity
Dec ’25
Call log
I read online that there is no way to extract the call log from an iPhone. I want to develop an app to help people remember to call their mom, and if they did, the "nagging" would disappear automatically. I'm looking for any workaround to know when a user called someone, without having them log it manually.
Replies
1
Boosts
0
Views
481
Activity
Dec ’25
CallKit VoIP → App launch → Auto WebRTC/MobileRTC connection: Does Apple allow this flow?
Our app receives a CallKit VoIP call. When the user taps “Answer”, the app launches and automatically connects to a real-time audio session using WebRTC or MobileRTC. We would like to confirm whether the following flow (“CallKit Answer → app opens → automatic WebRTC or MobileRTC audio session connection”) complies with Apple’s VoIP Push / CallKit policy. In addition, our service also provides real-time video-class functionality using the Zoom Meeting SDK (MobileRTC). When an incoming CallKit VoIP call is answered, the app launches and the user is automatically taken to the Zoom-based video lesson flow: the app opens → the user is landed on the Zoom Meeting pre-meeting room → MobileRTC initializes immediately. In the pre-meeting room, audio and video streams can already be active and MobileRTC establishes a connection, but the actual meeting screen is not joined until the user explicitly taps “Join”. We would like to confirm whether this flow for video lessons (“CallKit Answer → app opens → pre-meeting room (audio/video active) → user taps ‘Join’ → enter actual meeting”) is also compliant with Apple’s VoIP Push and CallKit policy.
Replies
1
Boosts
0
Views
166
Activity
Dec ’25
Are notification pushes not being received when in Picture-in-Picture mode?
Hello, I recently had an unusual experience, and I’m wondering if this is related to Apple’s policies, so I wanted to ask. While a call is in Picture-in-Picture (PIP) mode, notification pushes from the same app do not appear. The API is being triggered, but the notification banner does not show on the device. Once PIP is closed, the notifications start appearing normally again. Is this behavior enforced by Apple’s policies? What’s interesting is that banners from other apps do appear — only the banners from the app currently in PIP are not shown.
Replies
1
Boosts
0
Views
299
Activity
Dec ’25
CallKit issue
In iOS 26.1, after my app answers a VoIP call on the lock screen, tapping the bottom-left "More" button doesn't bring up the app icon to jump to the app. The same scenario works normally on iOS 26. How can I resolve this issue?
Replies
1
Boosts
1
Views
158
Activity
Dec ’25
VoIP Push Notifications Not Delivered in Background/Killed State (Using AppDelegate)
Hello, colleagues. I am reaching out to the community with an issue that is likely quite common. Unfortunately, I have not been able to resolve it independently and would like to confirm if my approach is correct. Core Problem: VoIP push notifications are not delivered to the application when it is in the background or terminated. After reviewing existing discussions on the forum, I concluded that the cause might be related to CallKit not having enough time to register. However, in my case, I am using AppDelegate, and in theory, CallKit registration should occur quickly enough. Nevertheless, the issue persists. Additional Question: I would also like to clarify the possibility of customizing the CallKit interface. Specifically, I am interested in adding custom buttons (for example, to open a door). Please advise if such functionality is supported by CallKit itself, or if a different approach is required for its implementation. Thank you in advance for your time and attention to my questions. For a more detailed analysis, I have attached a fragment of my code below. I hope this will help clarify the situation. Main File @main struct smartappApp: App { @UIApplicationDelegateAdaptor private var delegate: AppDelegate @StateObject private var navigationManager = NavigationManager() init() { print("Xct") if !isRunningTests() { DILocator.instance .registerModules([ ConfigModule(), SipModule(), AuthModule(), NetworkModule(), CoreDataModule(), RepositoryModule(), DataUseCaseModule(), SipUseCaseModule() ]) } } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("Axtest") completionHandler(.newData) } var body: some Scene { App Delegate File class AppDelegate: UIResponder, UIApplicationDelegate { private let voipRegistry = PKPushRegistry(queue: .main) private var provider: CXProvider? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { setupPushKit() setupCallKit() return true } public func regist(){ setupPushKit() setupCallKit() } private func setupPushKit() { voipRegistry.delegate = self voipRegistry.desiredPushTypes = [.voIP] DispatchQueue.main.async { self.voipRegistry.pushToken(for: .voIP) } } // MARK: - CallKit Setup private func setupCallKit() { let configuration = CXProviderConfiguration(localizedName: "MyApp") configuration.maximumCallGroups = 1 configuration.maximumCallsPerCallGroup = 1 configuration.supportsVideo = true configuration.iconTemplateImageData = UIImage(named: "callIcon")?.pngData() provider = CXProvider(configuration: configuration) provider?.setDelegate(self, queue: .main) } // MARK: - Background Launch Handling func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("Axtest") completionHandler(.newData) } } extension AppDelegate: PKPushRegistryDelegate { func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) { APNsImpl().registerToken(token: pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()) } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) { guard type == .voIP else { return } print("call kit") let payloadDict = payload.dictionaryPayload let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .phoneNumber, value: "dsfsdfddsf") update.hasVideo = payloadDict["hasVideo"] as? Bool ?? false provider?.reportNewIncomingCall(with: UUID(), update: update, completion: { error in if let error = error { print("Failed to report incoming call: \(error.localizedDescription)") } else { print("Successfully reported incoming call") } }) } }
Replies
1
Boosts
0
Views
273
Activity
Dec ’25
Critical CallKit Issue: Audio Route Flapping due to reason: 3 (CategoryChange) after User Toggle
I am facing a severe audio routing instability issue when using CallKit and the Zego Express SDK on iOS. The problem is that the audio route immediately reverts from the Speaker back to the Earpiece, effectively disabling the Speaker button functionality.📝 Observed BehaviorWhen the user taps the native CallKit Speaker Button, the audio route is correctly changed to the Speaker, but then instantly flips back to the Receiver (Earpiece), as shown in the system log captured via AVAudioSession.routeChangeNotification monitoring.🧾 Log Evidence (Flapping Occurs in 0.4 seconds)The following log snippet clearly illustrates the system overriding the user's action (reason: 4) with an unexpected CategoryChange (reason: 3) event: TimestampComponentReason CodeDescriptionRouteIs Speaker16:31:18.009[CallKitManager]4Override (CallKit/ControlCenter)Loa ngoài (Speaker)true16:31:18.411[CallKitManager]3CategoryChangeThiết bị nhận (Receiver)false
Replies
1
Boosts
0
Views
351
Activity
Dec ’25
iOS 26: Unable to Transition from CallKit Screen to App when remoteHandle is nil or empty string
Hello, I am developing an internal phone application using CallKit. I am experiencing an issue with the behavior of remoteHandle settings in iOS 26 and would appreciate any insights you can provide towards a solution. 1. Problem Description When an iPhone running iOS 26 is in a sleep state and receives a VoIP incoming call where remoteHandle is set to nil or an empty string (@""), we are unable to transition to our application (the UIExtension provided by the provider) from the CallKit UI's "More" (…) button after answering the call. 2. Conditions and Symptoms OS Version: iOS 26 Initial State: iPhone is in a sleep state Call Type: An unsolicited(unknown number) VoIP incoming call where the CXCallUpdate's remoteHandle is set to either nil or [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:@""] Symptoms: After answering the VoIP call by sliding the button, selecting the "More" (…) button displayed on the CallKit screen does not launch our application's UIExtension (custom UI), and the iPhone instead stay to the CallKit screen. 3. Previous Behavior (Up to iOS 18) Up to iOS 18, even when remoteHandle was set to an empty string using the following code, the application would transition normally from "More" after answering an incoming call from a sleep state. CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:@""]; [provider reportNewIncomingCallWithUUID:uuid update:update completion:completion]; 4. Unsuccessful Attempts to Resolve The issue remained unresolved after changing the handling for unsolicited(unknown number) incoming calls as follows: CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = nil; // Set remoteHandle to nil [provider reportNewIncomingCallWithUUID:uuid update:update completion:completion]; 5. Workaround (Temporary) The problem can be resolved, and the application can transition successfully, by setting a dummy numerical value (e.g., "0") for the value in remoteHandle using the following code: CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:@"0"]; // Set a dummy numerical value [provider reportNewIncomingCallWithUUID:uuid update:update completion:completion]; 6. Additional Information If remoteHandle is correctly set with the caller's number (i.e., not an unsolicited(unknown number) call; e.g., value:@"1234567890"), the application transitions normally from the "More" button after answering an incoming call from a sleep state, even in iOS 26. The above issue does not occur when answering incoming calls while the iPhone is in an active state (not sleeping). 7. Questions Have there been any other reports of similar behavior? Should this be considered a bug in CallKit for iOS 26? Should I make file a new Feedback report? Is there a suitable method to resolve this issue when the caller ID is unsolicited (nil or an empty string)? This problem significantly impacts user operations as end-users are unable to perform essential in-app actions such as hold or transfer after answering an unsolicited(unknown number) call from a sleep state. We are eager to find an urgent solution and would appreciate any information or advice you can provide. Thank you for your assistance.
Replies
5
Boosts
0
Views
657
Activity
Feb ’26
Is there a way to prevent the app from coming to the foreground when accepting a call with a banner-type call kit in a VoIP app?
I'm developing a VoIP app. Currently, I'm using CallKit to control call acceptance, and end-of-call processing. When a call comes in while using the phone, CallKit appears as a banner at the top of the screen. When I click "Accept" on the banner, the app opens and the call is received. (For OEMs, clicking the "Accept" button in the banner will accept the call as is.) The reason this feature is needed is, for example, when a call comes in as a banner call while using a navigation app, accepting the call causes the navigation app to go to the back and the VoIP app to come to the foreground, causing inconvenience to customers. This needs to be improved. Please advise.
Replies
1
Boosts
0
Views
144
Activity
Dec ’25
CXCallDirectoryProvider – Numbers added but blocking not working
Hi all, I'm working on a Call Directory Extension using CXCallDirectoryExtensionContext. I want to add a list of numbers to be blocked. Here's the function I use: override func beginRequest(with context: CXCallDirectoryExtensionContext) { context.delegate = self let blockedNumbers = loadNumberEntries(forKey: blockedKey) let identifiedNumbers = loadNumberEntries(forKey: identifiedKey) addAllBlocking(blockedNumbers, to: context) addAllIdentification(identifiedNumbers, to: context) context.completeRequest() } private func addAllBlocking(_ entries: [NumberEntry], to context: CXCallDirectoryExtensionContext) { let numbers: [Int64] = entries.compactMap { Int64($0.countryCode + $0.phone) }.sorted() for number in numbers { context.addBlockingEntry(withNextSequentialPhoneNumber: number) print("# Added blocking entry: \(number)") } } When I run this, I see in the console: # Added blocking entry: (*my number with country code*) So it seems the number is added correctly. However, in practice, the number is not blocked on the device. I’ve made sure that: The number is stored with the country code prefix. The extension is enabled in Settings → Phone → Call Blocking & Identification. The extension is reloaded after adding numbers. The array of numbers is sorted in ascending order before calling addBlockingEntry. Despite all this, the number still isn’t blocked. Does anyone know why the print shows the number added, but it doesn’t actually block the call? Am I missing something in the way CXCallDirectoryExtensionContext works? Thanks for any advice!
Replies
1
Boosts
0
Views
957
Activity
Jan ’26
CallKit automatically shows a system top toast after iOS 26, how to dismiss it?
I’m developing an iOS app that integrates with CallKit. Starting from iOS 26, I’ve noticed that the system automatically presents a top banner / toast-style UI when a CallKit call becomes active (see attached screenshot). This UI appears to be fully managed by the system. On iOS versions prior to iOS 26, this UI did not appear under the same CallKit configuration. What I’ve observed The banner is displayed automatically by the system It appears at the top of the screen, similar to a toast or call status banner It is not a view created by my app I could not find any public API or CallKit configuration related to dismissing or controlling it My questions: Is this top banner an intended system behavior change in newer iOS versions? Is there any public API to dismiss, hide, or customize this UI? If not, is this UI considered non-dismissible by design? Any clarification on the expected behavior or recommended approach would be greatly appreciated.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
4
Boosts
0
Views
488
Activity
Apr ’26
long wait time for usernotifications.filtering entitlement
Hi, happy new year, I'm a Product Manager for a communications app that's currently in testflight. We requested the com.apple.developer.usernotifications.filtering entitlement on December 3rd, and have yet to receive a response from Apple. I understand that the holiday break may have gotten in the way, however it feels like we were lost in the queue as it's been 6 weeks with no response. Our app owner has checked-in inside appstoreconnect but has not received anything back. Is this common? Is there any process for getting a status update? Are we doing something wrong? Without this entitlement we cannot make the device ring in the background. The app is a voice and video messaging platform.
Replies
1
Boosts
2
Views
502
Activity
Jan ’26
What are the image requirements for the logo for Live Caller ID?
When Live Caller ID first came out I experimented with it and got it working using the Example PIR database. All my links from that time are now out of date and no longer work, however I seem to have found where the PIR database example and documentation has moved to (https://swiftpackageindex.com/apple/pir-service-example/main/documentation/pirservice/testinginstructionslivecalleridlookup) But what I can't find is an exact definition of the the logo size/max size/dimensions/format should be. My memory from that time is that it was very pernickety, and if things weren't exactly right, the logo wasn't displayed. I can remember the format had to be HEIC to get it to work. Looking through the documentation however, I can't see exact requirements specified. My question is - for the Live Caller ID logo what are the exact image requirements, and where are they documented?
Replies
0
Boosts
0
Views
217
Activity
Feb ’26
About audio playback panel after call end.
Dear Apple Support Team, Thank you for your continued support. I would like to inquire about the behavior of CallKit. Our company provides an office PBX extension phone application (iPhone app). When the iPhone is placed into sleep mode (screen off) and our app receives an incoming call, the following sequence sometimes results in an audio playback panel appearing at the bottom of the lock screen for a few seconds after the call ends(See attachment file for detail). Sequence to reproduce the issue: Put the iPhone into sleep mode (screen off). Receive an incoming call to our extension phone app. CallKit incoming call screen appears. Answer the call. Conduct the call. End the call from the peer. iOS versions with confirmed behavior: iOS 26.0: Not observed. iOS 26.2: Observed. iOS 26.3: Not observed. This behavior does not affect the call functionality itself; however, some users report that the temporary appearance of the audio playback panel feels unusual. If there is any known reason for this behavior or any recommended workaround, we would greatly appreciate your guidance. Additionally, if this is a known issue that was addressed in iOS 26.3, we would appreciate any information you can provide regarding that as well. Thank you very much for your assistance.
Replies
2
Boosts
0
Views
255
Activity
Feb ’26
New PushKit delegate in iOS 26.4
Starting in iOS 26.4, PushKit has introduced a new "didReceiveIncomingVoIPPushWithPayload" delegate, making it explicit whether or not an app is required to report a call for any given push. The new delegate passes in a PKVoIPPushMetadata object which includes a "mustReport" property. We have not documented the exact criteria that will cause a mustReport to return false, but those criteria currently include: The app being in the foreground at the point the push is received. The app being on an active call at the point the push is received. The system determines that delivery delays have made the call old enough that it may no longer be viable. When mustReport is false, apps should call the PushKit completion handler (as they previously have) but are otherwise not required to take any other action. __ Kevin Elliott DTS Engineer, CoreOS/Hardware
Replies
0
Boosts
0
Views
407
Activity
Feb ’26
iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call
iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call Description I have successfully implemented VoIP pushes for the Killed state, where CallKit triggers correctly. However, when the app is in the Background state (suspended), it consistently crashes with an NSInternalInconsistencyException. The app process is killed by the iOS Watchdog because it fails to satisfy the requirement of posting an incoming call in the same run loop as the push receipt, or the completion handler is not being released fast enough by the JS bridge. Environment React Native Version: .78 React Native CallKeep Version: 4.3.14 React Native VoIP Push Notification Version: 3.3.3 iOS Version: 18.x Device: Physical iPhone [iphone 13 pro] The Issue When a VoIP push arrives while the app is in the Background: pushRegistry:didReceiveIncomingPushWithPayload: is called. RNCallKeep.reportNewIncomingCall is triggered on the Main Thread. The app is terminated by the system before the CallKit UI is fully established or before the completion() closure is executed. Current Implementation (AppDelegate.swift) func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { let payloadDict = payload.dictionaryPayload let callerName = payloadDict["callerName"] as? String ?? "Unknown Caller" let callUUIDString = payloadDict["uuid"] as? String ?? UUID().uuidString let userGUID = payloadDict["guid"] as? String ?? "0" RNCallKeep.reportNewIncomingCall( callUUIDString, handle: userGUID, handleType: "generic", hasVideo: false, localizedCallerName: callerName, supportsHolding: true, supportsDTMF: true, supportsGrouping: true, supportsUngrouping: true, fromPushKit: true, payload: ["userGuid": userGUID], withCompletionHandler: { } ) RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue) completion() } Logs Exception Type: EXC_CRASH (SIGKILL) Exception Note: EXC_CORPSE_NOTIFY Termination Reason: TCC 1 | [CoreFoundation] Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push. Observed Behavior Killed State: Works perfectly. Foreground State: Works perfectly. Background State: The phone may vibrate once, but the app process is killed before the CallKit UI appears. Questions/Suspected Causes Is RNVoipPushNotificationManager.addCompletionHandler causing a delay in the background run loop that triggers the Watchdog? Should completion() be called immediately in Swift for the Background state, rather than waiting for VoipPushNotification.onVoipNotificationCompleted in JS? Is there a known issue with RNCallKeep not being able to present the UI while the app is in a suspended background state?
Replies
3
Boosts
0
Views
315
Activity
Feb ’26
Frequent providerDidReset Callbacks in Production
Hello, We're seeing a high rate of providerDidReset callbacks in production across a large user base (iOS 16, 17, 18, and 26). I'd like to understand both the correct way to handle this delegate method and strategies to reduce its frequency. Background The callback occurs across all iOS versions we support and is not isolated to a specific device or region. The callback can occur in any app state (foreground, background, inactive), however it is most dominant in the background state — particularly during VoIP push notification handling. The callback is more prevalent during long app sessions — for example, when the app has been running continuously for a day or overnight. We do not call CXProvider.invalidate() anywhere in our codebase explicitly. After providerDidReset fires, subsequent transactions fail with CXErrorCodeRequestTransactionErrorUnknownCallUUID (error code 4). Re-initializing the provider via initializeProvider() resolves this error. Our Implementation We use a singleton proxy class (CallKitProxy) that owns the CXProvider. Below is a simplified version — some logging and non-essential parts have been removed for brevity. @objcMembers public final class CallKitProxy: NSObject { private var cxProvider: CXProvider? private let cxCallController: CXCallController private let cxCallObserver: CXCallObserver private override init() { cxCallObserver = CXCallObserver() cxCallController = CXCallController() super.init() initializeProvider() cxCallObserver.setDelegate(self, queue: nil) } private func initializeProvider() { let configuration = providerConfiguration() cxProvider = CXProvider(configuration: configuration) cxProvider?.setDelegate(self, queue: nil) } private func providerConfiguration() -> CXProviderConfiguration { let soundName = SharedUDHelper.shared.string(forKey: .pushNotificationSoundNameForCall) let sound = CallNotificationSounds(name: soundName ?? "ringtoneDefault") let configuration = CXProviderConfiguration() configuration.supportsVideo = true configuration.maximumCallsPerCallGroup = 1 configuration.maximumCallGroups = 1 configuration.supportedHandleTypes = [.phoneNumber, .generic] configuration.iconTemplateImageData = UIImage( named: "callkit_mask", in: .main, compatibleWith: nil )?.pngData() configuration.ringtoneSound = sound.name return configuration } public func requestTransaction( action: CXCallAction, completion: @escaping (Error?) -> Void ) { let transaction = CXTransaction(action: action) cxCallController.request(transaction) { error in completion(error) } } } extension CallKitProxy: CXProviderDelegate { public func providerDidReset(_ provider: CXProvider) { // End any active calls, then re-initialize the provider initializeProvider() } } Questions 1. Is re-initializing the provider inside providerDidReset the correct approach? The documentation states that providerDidReset signals the provider has been reset and all calls should be considered terminated. Should we be calling CXProvider.invalidate() on the old instance before creating a new one? Or is assigning a new CXProvider to cxProvider (which releases the old instance) sufficient? 2. What could be causing providerDidReset to fire so frequently, and how can we reduce it? We're particularly concerned about cases triggered during VoIP push handling in the background and inactive states. Are there known conditions — such as provider configuration changes, app lifecycle events, or system memory pressure — that commonly trigger this callback? And are there any recommended patterns to make the provider more resilient in these scenarios? Thank you.
Replies
1
Boosts
0
Views
287
Activity
Mar ’26
Live Caller ID Lookup: does iOS call /queries even when the number is in Contacts?
Hi! We’ve had Live Caller ID Lookup in production for a while. We’re seeing backend RPS on our /queries endpoint much higher than our expected incoming call volume. While testing with Console.app during an incoming call, it looks like iOS may still hit our service even when the caller number is already in the user’s Contacts - but I’m not 100% sure from logs alone. Can you confirm: Does iOS invoke Live Caller ID Lookup (i.e. call /queries) for every incoming call, including calls from saved Contacts? If yes, is this simply expected framework behavior? Thanks!
Replies
0
Boosts
0
Views
314
Activity
Mar ’26
Questions about VoIP Push compliance rules and CallKit handling
Hello everyone, I’m an iOS developer working on a real-time communication app that supports VoIP calls using CallKit. The app has been in production for more than 5 years. Over the years, some users have occasionally reported that they do not receive incoming call pushes. We have tried multiple optimizations on both the client and server side, but the improvement has been limited. From Apple documentation and discussions online, I understand that iOS may restrict VoIP pushes if the system detects violations of VoIP push usage rules (for example, not presenting a CallKit call after receiving a VoIP push). However, the exact rules and thresholds for these violations are not clearly documented, so I’d like to ask a few questions to better understand the expected behavior. Below is a simplified description of our current call flow. Call Flow Caller When the user initiates a call: We do not use CallKit The call is handled entirely using a custom in-app call UI Callee When the user receives a call: Device locked or app in background A VoIP push wakes the app The app presents the CallKit incoming call UI App in foreground The server still sends a VoIP push The app first reports the call to CallKit After a very short delay, the app programmatically ends the CallKit call Then a custom in-app call UI is presented via the app's long connection The reason we always send a VoIP push (even when the app is in the foreground) is that we want to maximize call delivery reliability.
Replies
5
Boosts
0
Views
471
Activity
Mar ’26
Clarification on Allowed Uses of VoIP Push Notifications for Ending/Updating CallKit State
Hello, I’m implementing VoIP calling in an iOS application using PushKit (VoIP pushes) together with CallKit. The standard call flow works correctly: Happy scenario User A initiates a call. Server sends a VoIP push to User B. User B’s device receives the push and reports the incoming call using CallKit. User B answers the call. However, I would like clarification about non-happy scenarios and when it is acceptable to use VoIP pushes to update or stop a CallKit ringing state. Apple documentation warns that VoIP pushes must be used only when they result in a call-related action, so I want to ensure the following cases are compliant. Scenario A — Caller Cancels Before Answer User A calls User B. Server sends a VoIP push to User B. User B’s device starts ringing via CallKit. Before User B answers, User A cancels the call. Question: Is it acceptable to send another VoIP push to User B indicating that the call has been cancelled so the device can: stop the CallKit ringing UI end the call optionally mark it as missed or cancelled Or should this state change be handled using a regular remote push or another signaling mechanism instead of VoIP push? Scenario B — Callee Rejects the Call User B rejects the call from CallKit. The server must inform User A that the call was rejected. Question: Is it acceptable to send a VoIP push to User A to update the CallKit state and terminate the outgoing call UI? Scenario C — Multiple Devices per User User B may be logged in on multiple devices. User A calls User B. VoIP push is sent to all devices of User B. One device answers. Question: Is it acceptable to send a VoIP push to the remaining devices instructing them to: stop ringing end the CallKit incoming call UI Or is there a recommended alternative pattern for this case? Main Question Aside from the initial incoming call VoIP push, in which situations is it considered acceptable to send additional VoIP pushes to terminate or update CallKit state (cancelled, rejected, answered on another device)? The goal is to remain compliant with PushKit policies, particularly the guidance that VoIP pushes should only be used when they result in a call-related user action. Any guidance on the recommended architecture for these cases would be greatly appreciated. Thank you.
Replies
1
Boosts
0
Views
328
Activity
Mar ’26