CallKit Tutorial for iOS

Learn how your app can use CallKit for system-level phone integration and how to build a directory extension for call blocking and identification. By Andrew Kharchyshyn.

Leave a rating/review
Download materials
Save for later
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Creating a Call Directory Extension

The directory extension is a new extension point offered by CallKit. It allows your VoIP app to:

  • Add phone numbers to the system’s block list.
  • Identify incoming calls by their phone number or other uniquely identifying information such as email address.

When the system receives a call, it will check the address book for a match. If it doesn’t find one, it can also check in app-specific directory extensions. Why not add a directory extension to Hotline?

In Xcode, go to File ▸ New ▸ Target… and choose Call Directory Extension. Name it HotlineDirectory and click Finish. Xcode will automatically create a new file, CallDirectoryHandler.swift. Locate it in the Project navigator and see what’s inside.

The first method you’ll find is beginRequest(with:). Initializing your extension will invoke this method. In case of any errors, the extension will tell the host app to cancel the extension request by invoking requestFailed(for:withError:). It relies on two other methods to build the app-specific directory.

addAllBlockingPhoneNumbers(to:) will collect all the phone numbers that should be blocked. Replace its implementation with the following:

let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ 1234 ]
for phoneNumber in phoneNumbers {
  context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)

Invoking addBlockingEntry(withNextSequentialPhoneNumber:) with a given phone number will add it to the block list. The system telephony provider won’t display calls from a blocked number.

Now, take a look at addAllIdentificationPhoneNumbers(to:). Replace the method body with the code below:

let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ 1111 ]
let labels = [ "RW Tutorial Team" ]
for (phoneNumber, label) in zip(phoneNumbers, labels) {
    withNextSequentialPhoneNumber: phoneNumber, 
    label: label)

Invoking addIdentificationEntry(withNextSequentialPhoneNumber:label:) with a specified phone number and label will create a new identification entry. When the system receives a call from this number, the call UI will display the label that matches the user.

Settings Setup

It’s time to test your new extension. Build and run Hotline on your device. At this point your extension may not yet be active. To enable it, do the following steps:

  1. Go to the Settings app
  2. Select Phone
  3. Select Call Blocking & Identification
  4. Enable Hotline
Note: If you’re having trouble getting the system to recognize or use your extension, try killing the app and relaunching it. Sometimes iOS needs a little extra help to use your extension.

Testing a blocked call is easy. Launch Hotline and simulate an incoming call from the number 1234. You’ll notice that the system doesn’t report anything. In fact, if you put a breakpoint in the implementation of reportIncomingCall(uuid:handle:hasVideo:completion:) in ProviderDelegate, you’ll notice that reportNewIncomingCall(withupdate:completion:) will even report an error.

To test identifying calls, launch Hotline again and simulate a new call. This time, enter the number 1111. You’ll see the following call UI:

FYI: That’s not a real number. :]

FYI: That's not a real number. :]

This app is awesome!

This app is awesome!

Congratulations! You’ve created an app which leverages CallKit to provide a first-party VoIP experience! :]

Where to Go From Here?

Download the completed project using the Download Materials button at the top or bottom of this tutorial.

If you wish to learn more about CallKit, check out Session 230 from WWDC 2016.

I hope you enjoyed this CallKit tutorial. If you have any questions or comments, please join the forum discussion below!

Andrew Kharchyshyn


Andrew Kharchyshyn


József Vesza


Alex Figueroa

Tech Editor

Nicole Hardina


Aleksandra Kizevska


Richard Turton

Final Pass Editor

Richard Critz

Team Lead

Over 300 content creators. Join our team.