Framework

CallKit

Overview

Implement programmatic access to VoIP functionality, call blocking, and identification in your app.

Supporting VoIP Functionality

Apps can use CallKit to let users receive incoming calls and make outgoing calls using the system-provided phone UI.

Receiving Incoming Calls

To configure your app to receive incoming calls, first create a CXProvider object and store it for global access. An app reports an incoming call to the provider in response to an external notification, such as a VoIP push notification.

// MARK: PKPushRegistryDelegate
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
    // report new incoming call
}

Using the information provided by the external notification, the app creates a UUID and a CXCallUpdate object to uniquely identify the call and the caller, and passes them both to the provider using the reportNewIncomingCall(with:update:completion:) method.

if let uuidString = payload.dictionaryPayload["UUID"] as? String,
    let identifier = payload.dictionaryPayload["identifier"] as? String,
    let uuid = UUID(uuidString: uuidString)
{
    let update = CXCallUpdate()    
    update.callerIdentifier = identifier
    
    provider.reportNewIncomingCall(with: uuid, update: update) { error in
        // …
    }
}

After the call is connected, the system sends provider(_:perform:) to the provider delegate. In your implementation, the delegate is responsible for configuring an AVAudioSession and calling fulfill() on the action when finished.

func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
    // configure audio session
    action.fulfill()
}

Making Outgoing Calls

A user can initiate an outgoing call with a VoIP app in any of the following ways:

  • Performing an interaction within the app

  • Opening a link with a supported custom URL scheme

  • Initiating a VoIP call using Siri

To make an outgoing call, an app requests a CXStartCallAction from a CXCallController object. The action consists of a UUID to uniquely identify the call and a CXHandle object to specify the recipient.

let uuid = UUID()
let handle = CXHandle(type: .emailAddress, value: "jappleseed@apple.com")
 
let startCallAction = CXStartCallAction(call: uuid)
startCallAction.destination = handle
 
let transaction = CXTransaction(action: startCallAction)
callController.request(transaction) { error in
    if let error = error {
        print("Error requesting transaction: \(error)")
    } else {
        print("Requested transaction successfully")
    }
}

After the recipient answers the call, the system sends provider(_:perform:) to the provider delegate. In your implementation, the delegate is responsible for configuring an AVAudioSession and calling fulfill() on the action when finished.

func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
    // configure audio session
    action.fulfill()
}

Call Blocking and Identification

Apps can create a Call Directory app extension to identify and block incoming callers by their phone number.

Creating a Call Directory App Extension

You can create a Call Directory extension for your containing app by adding a new project target and selecting the Call Directory Extension template under Application Extensions.

You set up both identification and blocking of incoming calls in the implementation of the beginRequest(with:) method of the CXCallDirectoryProvider subclass of your Call Directory extension. This method is called when the system launches the app extension.

For more information about how app extensions work, see App Extension Programming Guide.

Identifying Incoming Callers

When a phone receives an incoming call, the system first consults the user’s contacts to find a matching phone number. If no match is found, the system then consults your app’s Call Directory extension to find a matching entry to identify the phone number. This is useful for applications that maintain a contact list for a user that’s separate from the system contacts, such as a social network, or for identifying incoming calls that may be initiated from within the app, such as for customer service support or a delivery notification.

For example, consider a user who is friends with Jane in a social networking app, but who doesn’t have her phone number in their contacts. The social networking app has a Call Directory app extension, which downloads and add the phone numbers of all of the user’s friends. Because of this, when the user gets an incoming call from Jane, the system displays something like “(App Name) Caller ID: Jane Appleseed” rather than “Unknown Caller”.

To provide identifying information about incoming callers, you use the addIdentificationEntry(withNextSequentialPhoneNumber:label:) method in the implementation of beginRequest(with:).

class CustomCallDirectoryProvider: CXCallDirectoryProvider {
    override func beginRequest(with context: CXCallDirectoryExtensionContext) {
        let labelsKeyedByPhoneNumber: [CXCallDirectoryPhoneNumber: String] = [ … ]
        for (phoneNumber, label) in labelsKeyedByPhoneNumber.sorted(by: <) {
            context.addIdentificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label)        
        }

        context.completeRequest()
    }
}

Because this method is called only when the system launches the app extension and not for each individual call, you must specify call identification information all at once; you cannot, for example, make a request to a web service to find information about an incoming call.

Blocking Incoming Calls

When a phone receives an incoming call, the system first consults the user’s block list to determine whether a call should be blocked. If the phone number is not on a user- or system-defined block list, the system then consults your app’s Call Directory extension to find a matching blocked number. This is useful for apps that, for example, maintain a database of known solicitors, or allow the user to block any numbers that match a set of criteria.

To block incoming calls for a particular phone number, you use the addBlockingEntry(withNextSequentialPhoneNumber:) method in the implementation of beginRequest(with:).

class CustomCallDirectoryProvider: CXCallDirectoryProvider {
    override func beginRequest(with context: CXCallDirectoryExtensionContext) {
        let blockedPhoneNumbers: [CXCallDirectoryPhoneNumber] = [ … ]
        for phoneNumber in blockedPhoneNumbers.sorted(by: <) {
            context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)
        }
        
        context.completeRequest()
    }
}

Symbols

Classes

CXAction

An abstract class that declares a programmatic interface for objects that represent a telephony action.

CXAnswerCallAction

An encapsulation of the act of answering an incoming call.

CXCall

A telephony call.

CXCallAction

A programmatic interface for objects that represent a telephony action associated with a call object.

CXCallController

A programmatic interface for interacting with and observing calls.

CXCallDirectoryExtensionContext

A programmatic interface for adding identification and blocking entries to a Call Directory app extension.

CXCallDirectoryManager

The programmatic interface to an object that manages a Call Directory app extension.

CXCallDirectoryProvider

The principal object for a Call Directory app extension for a host app.

CXCallObserver

A programmatic interface for an object that manages a list of active calls and observes call changes.

CXCallUpdate

An encapsulation of new and changed information about a call.

CXEndCallAction

An encapsulation of the act of ending a call.

CXHandle

A means by which a call recipient can be reached, such as a phone number or email address.

CXPlayDTMFCallAction

An encapsulation of the act of playing a DTMF (dual tone multifrequency) sequence.

CXProvider

An object that represents a telephony provider.

CXProviderConfiguration

An encapsulation of the configuration of a provider object.

CXSetGroupCallAction

An encapsulation of the act of grouping or ungrouping calls.

CXSetHeldCallAction

An encapsulation of the act of placing a call on hold or removing a call from hold.

CXSetMutedCallAction

An encapsulation of the act of muting or unmuting a call.

CXStartCallAction

An encapsulation of the act of initiating an outgoing call.

CXTransaction

An object that contains zero or more action objects to be performed by a call controller.

Protocols

CXCallDirectoryExtensionContextDelegate

A collection of methods that are called by a Call Directory extension context object when a request fails.

CXCallObserverDelegate

A collection of methods that are called by a call observer object when a call changes state.

CXProviderDelegate

A collection of methods that are called by a telephony provider object.