CallKit – How to Configure It?

CallKit – How to Configure It?

iOS 10 offers many new features. One of them is CallKit, the framework which allows our application to seamlessly integrate with the user interface of a phone. CallKit may be used in applications to allow users to receive incoming calls and perform outgoing calls with the phone-provided UI. VoIP call can be muted or suspended. It is also possible to make video calls.

Preparing the project

The first step is to prepare receiving VoIP notifications.

Background modes - Voice over IP

Configuring VoIP notifications

To configure the application to receive notifications, import framework PushKit to our AppDelegate file and create an object PKPushRegistry. Be sure to set the delegate of the newly created object as self, and set its type as VoIP:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
        let pushRegistry = PKPushRegistry(queue: DispatchQueue.main)
        pushRegistry.delegate = self
        pushRegistry.desiredPushTypes = [.voIP]

        return true
    }

Functions used for storing credentials on the server for the active user and processing pushs are:

func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, forType type: PKPushType) {
            //Store push credentials on server for the active user.
    }

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
    }

Supporting received notifications

The final step is to parse the data received from the function didReceiveIncomingPushWith, which, among other things, can wake the phone from the state of being locked.

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
        guard type == .voIP else { return }

        if let uuidString = payload.dictionaryPayload["UUID"] as? String,
           let handle = payload.dictionaryPayload["handle"] as? String,
           let hasVideo = payload.dictionaryPayload["hasVideo"] as? Bool,
           let uuid = UUID(uuidString: uuidString)
        {
             // Handle incoming call
        }
}

Setting up CallKit

The first step is to create a class to handle incoming calls by extending the class CXProviderDelegate.

final class ProviderDelegate: NSObject, CXProviderDelegate {
    private let provider: CXProvider
}

The next step is to configure the provider.

static var providerConfiguration: CXProviderConfiguration {
        let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "name")
        let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)

        providerConfiguration.supportsVideo = true

        providerConfiguration.maximumCallsPerCallGroup = 1

        providerConfiguration.supportedHandleTypes = [.phoneNumber]

        if let iconMaskImage = UIImage(named: "wideo") {
            providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage)
        }

        providerConfiguration.ringtoneSound = "Ringtone.caf"

        return providerConfiguration
}

The last step is to provide an initializer, add the reportIncomingCall function responsible for the transfer of an incoming call to the system and to add providerDidReset function which is called when the provider is restarted.

init() {
        provider = CXProvider(configuration: type(of: self).providerConfiguration)
        super.init()
        provider.setDelegate(self, queue: nil)
}

func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)? = nil) {
        // Construct a CXCallUpdate describing the incoming call, including the caller.
        let update = CXCallUpdate()
        update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
        update.hasVideo = hasVideo

        // Report the incoming call to the system
        provider.reportNewIncomingCall(with: uuid, update: update) { error in
            completion?(error as? NSError)
        }
}

func providerDidReset(_ provider: CXProvider) {
        print("Provider did reset")
        /*
            End any ongoing calls if the provider resets, and remove them from the app's list of calls,
            since they are no longer valid.
         */
    }

This is only an introduction, and if you would like to learn more about this, I recommend reading this.

You can find a lot of information and a sample application there.

Wojtek

Wojtek Byczkowski

iOS Developer at Holdapp for 5 years. Wojtek believes that less is more in software development and always puts efficiency first when working on projects. Apart from programming, he also has a passion for sports. If you’d like to talk about football or speedway, Wojtek’s definitely your man.

Learn more

Bitrise Tests Made Easier: Update JIRA Issues with Build Number and Forget About Delays in QA Testing

When you trigger Bitrise build with changes and forget to tell QA specialists some essential information, there are two likely scenarios. You waste time waiting for the update from the tester, only you don’t know it’s never coming. Or you get so many questions about builds that you can’t keep up. Sounds familiar? If so, let us tell you about the JIRA issue update that keeps workflow in order.

Read more

How to Send iOS Notifications in Different Languages? Guide to Dynamic Localization

The best way to set a connection between a user, provider, and an app? System notifications. They allow users to get the latest news in no time. This solution is easy to implement in apps dedicated to one market. But it gets complicated when the messages must be displayed in many languages. In such cases, the dynamic localization of remote notifications can be a real game-changer.

Read more

WebSockets on iOS – Real-time Communication That Doesn’t Slow Down the App

When you want to download data for the app, you probably use API RESTful interface. All it takes is to ask the server for the data and that’s it! This method works well when the app doesn’t need permanent access to new information. But what to do if the content has to be updated in real-time? A delay can make it impossible for the user to buy an item or make a sports bet, for example. But there’s a solution – WebSockets on iOS. Check out why you should implement them, and how to do it.

Read more

Project estimation

Let us know what product you want to build and how we can help you.

Why choose us?

Logo Mobile Trends Awards

Mobile Trends Awards 2017

Nomination in
M-COMMERCE category

Logo Legalni bukmacherzy

Legal Bookmakers Award 2019

Best Mobile App

Mobile Trends Awards logo

Mobile Trends Awards 2020

Nomination in SPORT & RECREATION category

17

client reviews

Clutch logo