Introduction to CallKit

CallKit iOS, Audio call support in iOS app, Video Call support in iOS app

Introduction to CallKit

CallKit iOS, Audio call support in iOS app, Video Call support in iOS app

In this blog, i am focusing only on CallKit framework, in next blog i will be covering Intent extension and PushKit framework. Lets start!

Life on iOS wasn’t always perfect for VoIP app developers.Luckily, Apple introduced CallKit in iOS 10 to change all that!

How do VoIP apps work today?

Overview

CallKit lets you integrates system services(Bluetooth, Siri, Face time, Phone App) with your VoIP Service. It provides the calling interface of phone app and your VoIP Service need to take care of back-end communication.
For incoming and outgoing calls, CallKit displays the same interfaces as the Phone app, giving your app a more native look and feel.
CallKit lets you responds appropriately to system-level behaviors such as Do Not Disturb, Low network connectivity.

In addition to handling calls, you can provide a Call Directory app extension to provide caller ID information and a list of blocked numbers associated with your service.

Basic CallKit Concepts

Now that you know what CallKit is all about, let’s take a closer look at a few fundamental concepts you’ll need in order to understand and make use of it.

  • CXProvider Create single instance of CXProvider and use throughout your VoIP app, its object is responsible for reporting out-of-band notifications that occur to the system.Initialize a new provider instance with the supplied configuration.
let provider: CXProvider = CXProvider(configuration: type(of: self).providerConfiguration)
  • CXProviderConfiguration The app’s provider configuration, representing its CallKit capabilities, you can configure below properties:
    - Localized name of the provider, ex: Name of application
    - ringtoneSound, Name of resource in app’s bundle to play as ringtone for incoming call, ex: “MyRingtone.aif”
    - MaximumCallGroups , Default is 2
    - MaximumCallsPerCallGroup, Default is 5
    - Whether this provider’s calls should be included in the system’s Recents list at the end of each call (includesCallsInRecents).
    - SupportsVideo, whether VoIP service supports video or not, Default isNO
    - SupportedHandleTypes (CXHandleType), ex: supportedHandleTypes = [.phoneNumber]

static var providerConfiguration: CXProviderConfiguration {
let localizedName = NSLocalizedString(“APPLICATION_NAME”, comment: “Name of application”)
let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)
providerConfiguration.supportsVideo = true
providerConfiguration.maximumCallsPerCallGroup = 1
providerConfiguration.supportedHandleTypes = [.phoneNumber]
if let iconMaskImage = UIImage(named: “myMask”) {
providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage)
}
providerConfiguration.ringtoneSound = “Ringtone.aif”
return providerConfiguration
}
  • CXProviderDelegate protocol defines a set of methods that are called by an object that represents a telephony provider when the provider begins or resets, a transaction is requested, an action is performed, or an audio session changes its activation state. let’s take a closer look :
    - Handling provider events, Called when the provider begins or provider is reset.
    - Determining the executions of transactions,Called when a transaction is executed by a call controller.
    - Handling call actions, Called when the provider performs the specified start/answer/end/hold/muted/group/DTMF (dual tone multifrequency) call action
    - Handling changes to audio session activation state, called when the provider’s audio session is activated/deactivated.
CXProviderDelegate callback functions

Incoming Calls

When a PushKit notification indicates an incoming call, you generate an appropriate action. CallKit handles the action by presenting the system interface for answering the call.

When an incoming call is allowed by the system and approved by the user, the provider sends provider(_:perform:) to its delegate (as mentioned above in this blog). The provider’s delegate calls the fulfill()method to indicate that the action was successfully performed. To indicate that the call connected at a time other than the current time, you can instead call the fulfill(withDateConnected:).

//local function which reportNewIncomingCall function of CXProvider class to report it to the system
func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((Error?) -> Void)? = nil)
//Signal to the system that the action has been successfully performed.In delegate callbacks like below
action.fulfill()

In your local reportIncomingCall function, Construct a CXCallUpdate describing the incoming call, including the caller.
CXCallUpdate objects are used by the system to communicate changes to calls over time.

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
}

Only add incoming call to the app’s list of calls if the call was allowed (i.e. there was no error), Since calls may be “denied” for various legitimate reasons. See CXErrorCodeIncomingCallError for more detail.

Outgoing Calls

Start outgoing calls with a call controller, and handle subsequent interactions with your provider delegate.

CXCallController objects interact with call by performing actions.You can request that one or more actions be performed in a single CXTransaction object using the request(_:completion:) method.

Call activity may come from phone app or from any other system services, We need to provide interface such that our app can handle that events.

openUrl and continueUserActivity functions

These above functions need to override for providing the start call interface to system services.
When the telephony provider receives an incoming call or the user starts an outgoing call, the other caller is identified by a CXHandle object. For a caller identified by a phone number, the handle type is CXHandle.HandleType.phoneNumber and the value is a sequence of digits. For a caller identified by an email address, the handle type is CXHandle.HandleType.emailAddress and the value is an email address. For a caller identified in any other way, the handle type is CXHandle.HandleType.generic and the value typically follows some domain-specific format, such as a username, numeric ID, or URL.

CXStartCallAction is a concrete subclass of CXCallAction. When the user initiates an outgoing call, the provider sends provider(_:perform:) to its delegate. The provider’s delegate calls the fulfill() method to indicate that the action was successfully performed.

CXTransaction An object that contains zero or more action objects to be performed by a call controller. it addAction such as CXStartCallAction ,CXEndCallAction, CXSetHeldCallAction.

Hope you like this article, Please ❤️ to recommend this post to others 😊. Let me know your feedback. :)

References:

  1. https://developer.apple.com/documentation/callkit