callkit-voip▌
dpearson2699/swift-ios-skills · updated Apr 8, 2026
Build VoIP calling features that integrate with the native iOS call UI using
- ›CallKit and PushKit. Covers incoming/outgoing call flows, VoIP push
- ›registration, audio session coordination, and call directory extensions.
- ›Targets Swift 6.2 / iOS 26+.
CallKit + PushKit VoIP
Build VoIP calling features that integrate with the native iOS call UI using CallKit and PushKit. Covers incoming/outgoing call flows, VoIP push registration, audio session coordination, and call directory extensions. Targets Swift 6.2 / iOS 26+.
Contents
- Setup
- Provider Configuration
- Incoming Call Flow
- Outgoing Call Flow
- PushKit VoIP Registration
- Audio Session Coordination
- Call Directory Extension
- Common Mistakes
- Review Checklist
- References
Setup
Project Configuration
- Enable the Voice over IP background mode in Signing & Capabilities
- Add the Push Notifications capability
- For call directory extensions, add a Call Directory Extension target
Key Types
| Type | Role |
|---|---|
CXProvider |
Reports calls to the system, receives call actions |
CXCallController |
Requests call actions (start, end, hold, mute) |
CXCallUpdate |
Describes call metadata (caller name, video, handle) |
CXProviderDelegate |
Handles system call actions and audio session events |
PKPushRegistry |
Registers for and receives VoIP push notifications |
Provider Configuration
Create a single CXProvider at app launch and keep it alive for the app
lifetime. Configure it with a CXProviderConfiguration that describes your
calling capabilities.
import CallKit
/// CXProvider dispatches all delegate calls to the queue passed to `setDelegate(_:queue:)`.
/// The `let` properties are initialized once and never mutated, making this type
/// safe to share across concurrency domains despite @unchecked Sendable.
final class CallManager: NSObject, @unchecked Sendable {
static let shared = CallManager()
let provider: CXProvider
let callController = CXCallController()
private override init() {
let config = CXProviderConfiguration()
config.localizedName = "My VoIP App"
config.supportsVideo = true
config.maximumCallsPerCallGroup = 1
config.maximumCallGroups = 2
config.supportedHandleTypes = [.phoneNumber, .emailAddress]
config.includesCallsInRecents = true
provider = CXProvider(configuration: config)
super.init()
provider.setDelegate(self, queue: nil)
}
}
Incoming Call Flow
When a VoIP push arrives, report the incoming call to CallKit immediately. The system displays the native call UI. You must report the call before the PushKit completion handler returns -- failure to do so causes the system to terminate your app.
func reportIncomingCall(
uuid: UUID,
handle: String,
hasVideo: Bool
) async throws {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
update.hasVideo = hasVideo
update.localizedCallerName = "Jane Doe"
try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<Void, Error>) in
provider.reportNewIncomingCall(
with: uuid,
update: update
) { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}
}
}
Handling the Answer Action
Implement CXProviderDelegate to respond when the user answers:
extension CallManager: CXProviderDelegate {
func providerDidReset(_ provider: CXProvider) {
// End all calls, reset audio
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// Configure audio, connect to call server
configureAudioSession()
connectToCallServer(callUUID: action.callUUID)
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
disconnectFromCallServer(callUUID: action.callUUID)
action.fulfill()
}
}
Outgoing Call Flow
Use CXCallController to request an outgoing call. The system routes the
request through your CXProviderDelegate.
func startOutgoingCall(handle: String, hasVideo: Bool) {
let uuid = UUID()
let handle = CXHandle(type: .phoneNumber, value: handle)
let startAction = CXStartCallAction(call: uuid, handle: handle)
startAction.isVideo = hasVideo
let transaction = CXTransaction(action: startAction)
callController.request(transaction) { error in
if let error {
print("Failed to start call: \(error)")
}
}
}
Delegate Methods for Outgoing Calls
extension CallManager {
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
configureAudioSession()
// Begin connecting to server
provider.reportOutgoingCall(
with: action.callUUID,
startedConnectingAt: Date()
)
connectToServer(callUUID: action.callUUID) {
provider.reportOutgoingCall(
with: action.callUUID,
connectedAt: Date()
)
}
action.fulfill()
}
}
PushKit VoIP Registration
Register for VoIP pushes at every app launch. Send the token to your server whenever it changes.
import PushKit
final class PushManager: NSObject, PKPushRegistryDelegate {
let registry: PKPushRegistry
override init() {
registry = PKPushRegistry(queue: Discussion
Product Hunt–style comments (not star reviews)- No comments yet — start the thread.
Ratings
4.5★★★★★47 reviews- ★★★★★Evelyn Okafor· Dec 20, 2024
I recommend callkit-voip for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
- ★★★★★Amina Ghosh· Dec 16, 2024
Useful defaults in callkit-voip — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
- ★★★★★Dhruvi Jain· Dec 8, 2024
Solid pick for teams standardizing on skills: callkit-voip is focused, and the summary matches what you get after install.
- ★★★★★Mateo Chawla· Dec 4, 2024
callkit-voip reduced setup friction for our internal harness; good balance of opinion and flexibility.
- ★★★★★Oshnikdeep· Nov 27, 2024
We added callkit-voip from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.
- ★★★★★Evelyn Kapoor· Nov 23, 2024
I recommend callkit-voip for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
- ★★★★★Diya Bhatia· Nov 11, 2024
callkit-voip reduced setup friction for our internal harness; good balance of opinion and flexibility.
- ★★★★★Fatima Martinez· Nov 7, 2024
Registry listing for callkit-voip matched our evaluation — installs cleanly and behaves as described in the markdown.
- ★★★★★Evelyn Sanchez· Nov 3, 2024
Keeps context tight: callkit-voip is the kind of skill you can hand to a new teammate without a long onboarding doc.
- ★★★★★Amina Diallo· Oct 26, 2024
callkit-voip reduced setup friction for our internal harness; good balance of opinion and flexibility.
showing 1-10 of 47