Business Productivity
How to Integrate Apple’s CallKit into iOS Applications Using the Amazon Chime SDK
Apple’s CallKit is a framework introduced with iOS 10. It gives users the ability to handle VoIP calls from third party apps, such as Skype, similar to how they would handle a system phone call. If your iOS application is currently using Amazon Chime SDK without Apple’s CallKit, you will notice that in-application audio cannot be started while a phone call or a call from another Apple CallKit-enabled application is in progress. This is because Apple CallKit enabled calls have higher priority than ones without Apple’s CallKit enabled. In addition, without Apple’s CallKit, providing call history and enabling preferred user settings to silence calls, alerts, and notifications in your application is not possible.
With Apple CallKit integration, the user can be given the choice to end an in-progress call and start a new VoIP call or online meeting from your iOS application that integrates Amazon Chime SDK features (“Customer Application”). Integrating Apple’s CallKit also gives your Customer Application a more native look and feel by providing the same UI as the iOS Phone app, logging the call history in the iOS Phone app, and respecting system settings such as Do Not Disturb.
Solution overview
The following sections walk through key steps to integrate Apple’s CallKit into your Customer Application and wire up relevant Amazon Chime SDK APIs to initiate outgoing and incoming VoIP calls using Apple’s CallKit, end the call, and handle events during a call such as mute/unmute and hold/resume. This blog will focus on the main Apple CallKit functionalities related to Amazon Chime SDK for iOS. Topics such as iOS VoIP Push Notification, iOS Call Directory app extension will not be covered in this blog.
All the code samples used in this blog can be found in the demo app in our Amazon Chime SDK for iOS Github repository.
Note: Deploying this demo and receiving traffic from the demo created in this post can incur AWS charges.
Prerequisites
- You have read Building a Meeting Application on iOS using the Amazon Chime SDK. You understand the basic architecture of Amazon Chime SDK and have deployed a serverless/browser demo meeting application.
- Your Customer Application is integrated with Amazon Chime SDK for iOS.
- You have a basic to intermediate understanding of iOS development and tools.
- You have installed Xcode version 11.0 or later.
Note: To answer incoming VoIP calls through VoIP Push Notification, the Customer Application also needs to have VoIP Push Notification integrated.
Key steps
- Configure the Customer Application
- Initialize CXProvider and CXCallController
- Start outgoing call
- Report new incoming call
- Configure AVAudioSession
- Start Amazon Chime SDK meeting session
- Mute/Unmute call
- Handle call holding
- End call
- Test
- Cleanup
Configure the application
Assuming the Customer Application is already integrated with Amazon Chime SDK without Apple’s CallKit, enable Voice over IP
background mode in Signing & Capabilities
tab of the Project file:
Initialize CXProvider and CXCallController
There are three key classes to get familiar with when using Apple’s CallKit: CXProviderDelegate, CXProvider, CXCallController.
Refer to official Apple Documentation regarding their detailed responsibilities.
CXProviderDelegate
Implement CXProviderDelegate
’s methods to handle events throughout the incoming/outgoing call’s life cycle. These methods are discussed in more detail below.
CXProvider
Only create one instance of CXProvider
in the Customer Application. Initialize with CXProviderConfiguration and set up its delegate.
It’s used to report new incoming calls from events such as VoIP push notifications.
CXCallController
CXCallController
is used to perform actions on a call from within the Customer Application, not from Apple’s CallKit UI. These actions include: starting an outgoing call, ending a call, toggling mute, toggling hold.
Start outgoing call
Associate each Amazon Chime SDK MeetingSession as a call with a unique UUID. This UUID is used to identify the call in CXProviderDelegate
methods later on. CXHandle is used to identify the other caller in the iOS Phone application call history. Use CXCallController
to start the outgoing call. There is no Apple CallKit UI in this case.
Report new incoming call
After receiving a VoIP Push Notification for an incoming call, associate the call with a MeetingSession and use CXProvider
to report the call to trigger Apple’s CallKit Answer UI. There are two scenarios when the user answers the call:
- When the Customer Application is in the foreground or background, the Customer Application will be brought to the foreground after the user clicks Answer button on the Apple CallKit Answer UI. Apple’s CallKit UI is in the background in this scenario.
- When the device is locked, user stays on the Apple CallKit UI after sliding to answer. The user can tap the last button to unlock the device and be brought to the Customer Application.
The user can also choose to decline the call. Optionally, the user can start a timer that ends the incoming call if it’s not answered within a period of time. This call will show in the iOS Phone application call history as Missed Call in Red.
Configure AVAudioSession
Use the following code to configure AVAudioSession’s category and mode. Here is the documentation from Apple regarding why it’s necessary.
For outgoing call, this is added in:
For incoming call, this is added in:
Start Chime SDK meeting session
After AVAudioSession
is activated for incoming/outgoing call, the following CXProviderDelegate
method will be invoked.
IMPORTANT: Make sure to call start(callKitEnabled: true)
on AudioVideoControllerFacade here but not before. Otherwise Audio will not start properly, similar to this issue.
In order for Apple’s CallKit to calculate duration for outgoing call, use the following two callbacks on AudioVideoObserver to report connecting and connected status:
Mute/Unmute call
User can mute/unmute the call by toggling the Mute button on the Apple CallKit UI. If user can mute/unmute within the Customer Application, use CXCallController
to perform this action:
Regardless of whether the Mute/Unmute action is triggered from Apple’s CallKit UI or within the Customer Application, the following method on CXProviderDelegate
will be called, where we call the corresponding Amazon Chime SDK API:
Handle call holding
When an interrupting PSTN or Apple CallKit call is answered, the following method on CXProviderDelegate
will be called to put active call on hold:
IMPORTANT: Do not call start(callKitEnabled: true)
here when action.isOnHold
is false
because provider(_:didActivate:)
will be invoked, which will call start(callKitEnabled: true)
there.
When the interrupting call is ended by the user, previous call will be automatically resumed. However this is not the case when the interrupting call is ended by the remote party. In this case use CXCallController
to perform a CXSetHeldCallAction
from within the Customer Application:
End call
User can end the call by tapping the End button on the Apple CallKit UI. If the call needs to be ended with in the Customer Application, such as an End button in the Customer Application or incoming call not answered after a period of time, use CXCallController
to end the call:
Regardless of whether the call is ended from Apple’s CallKit UI or within the Customer Application by requesting CXEndCallAction
, the following method on CXProviderDelegate
will be called. Invoke stop()
on AudioVideoControllerFacade
and do any necessary UI update in the Customer Application.
The following callback on AudioVideoObserver will be invoked after audio session stops, where we report to the CXProvider
that a call is ended at a given time for a particular reason.
Test
Now the Customer Application should be integrated with Apple’s CallKit, with the Amazon Chime SDK handling the audio, video, and communication to other relevant AWS services. After building and running the Customer Appplication on a physical iOS device, outgoing/incoming/missed calls should show in the iOS Phone application Call History with corresponding handle and duration. To test call holding, start an Apple CallKit meeting with Amazon Chime SDK in the Customer Application, then make a phone call or start an Apple CallKit call from another application.
Note: Apple’s CallKit does not work on iOS simulator.
Cleanup
If you no longer want to keep the demo active in your AWS account and wish to avoid incurring AWS charges, the demo resources can be removed by deleting the two AWS CloudFormation stacks created in the prerequisites that can be found in the AWS CloudFormation console.
Conclusion
This blog is a guide for developers to integrate Apple’s CallKit into their iOS applications while using Amazon Chime SDK for audio/video meetings and VoIP calling. CXProvider and CXCallController are used to initiate/end calls from within the Customer Application and to perform actions on active call to sync up with Apple’s CallKit UI. For the most up to date code sample for Apple CallKit integration, reference our iOS Demo app in Amazon Chime SDK for iOS Github repository. If you still have questions regarding Apple’s CallKit, other suggestions for improvements, or feature requests, please feel free to create an issue in the repository.