How to implement SwiftUI(iOS14+) video call with Azure Communication Services

Hyunwoo Sung

--

1:1 ACS test call

Intro

This article aims to show a work through of integrating ACS + ANH + CallKit + PushKit for SwiftUI iOS application. Yes right! all together at once. Sounds bit much though, you’ll get a nice working example after you go through this article.

ACS(Azure Communication Services) is fairly new to the industry(Pre release announced around Sep. 2020) and there are quite many voice chat service providers like Amazon, Twilio, and etc… But I chose ACS over other services because ACS integrates all the communication related services as one single service like connecting landline phone to the service(limited for now), text message, QnA chat bot. If you are keen to learn more about the service, please go to communication service overview.

Prerequisites(adopted from ACS quickstart tutorial and ANH quickstart tutorial)

For ANH prerequisites, please take option 2 of Create a certificate for Notification Hubs as we are going to use token-based authentication due to the service change for iOS13. See more detail here.

If you are having some trouble with above prerequisites, don’t worry it’s normal. Just read their manual and don’t miss what the manual says to do so then you’ll be fine. If you are still having some trouble with configuring above, please wait for my next article where I will be explaining those configuration step by step with detailed screenshots.

Project initialization

Create a new project

Create a new project with Product Name and Organization Identifier. You can change these name to whatever you want.

Product Name: AzureCommunicationVideoCallingSample

Organization Identifier: com.contoso

Hello world SwiftUI

When press Command + Option + p, preview canvas will display what the app will look like. Hello, world! for now.

Now create a Podfile to include ACS and ANH pods.

platform :ios, '13.0'use_frameworks!target 'AzureCommunicationVideoCallingSample' do    pod 'AzureCommunicationCalling', '~> 1.0.0-beta.8'    pod 'AzureNotificationHubs-iOS'end

Install pods by ‘pod install’ command

$pod install

Initial configuration

Now open the project as workspace.

Let’s create some plist to hold our ACS and ANH credentials.

Create DevSettings.plist, FirstUser.plist, SecondUser.plist and fill in values from above prerequisites section.

In order to read these plist values, we are going to create some helper methods. Create a folder named Helpers and create a file named Constants.swift.

Create another file named PListHelper.swift in same folder.

When you are done with above tasks, your folder structure will look like below.

Open AzureCommunicationVideoCallingSampleApp.swift and modify as below. We will read credentials and connection strings from DevSettings.plist, {First / Second}User.plist and fill in our constants for later use.

Tab navigations

This sample has 2 tabs. Home and Profile.

In order to create a tab navigation, we will create two views and define enum for each tab.

Create Views folder and HomeView.swift and ProfileView.swift inside the folder.

HomeView and ProfileView SwiftUI files

Change “Hello, World!” to tab name accordingly. for ex) “Home” and “Profile”

Next, create a folder named Enum and create Tabs.swift file with below content.

Open ContentView.swift and change as below.

Press Command + Option + P and note that tab bar navigation is applied as below.

TabView applied

Authentication

Create CommunicationUserTokenModel.swift and AuthenticationViewModel.swift as below.

This viewModel will initialize azure communication user token with constants that we defined earlier. You will have to modify this with your own token provider when applying to real project.

We will use getCommunicationUserToken function after implementing CallingViewModel shortly.

ViewModels

UIRepresentables

ACS renders stream with RenderView interface which conforms to UIView. In order to use this interface in SwiftUI, we have to use UIViewRepresentable.

Please visit here for detail about UIViewRepresentable.

Create VideoStreamView.swift file under Models folder and fill it with below content.

We will use this struct to present our local video and remote participants’ videos.

StreamViewModels

Create below files under Models folder.

Above classes will be handling video streams and indicators for mic / video.

Callkit manager

Create CallKitManager.swift under Models folder.

CallKit will give your app a native looking call experiences. Not only that there is one important reason that you have to use this CallKit that if you fail to report a call to CallKit after your app receives push notifications, the system will terminate your app. Read more here.

Configrue NotificationHubs

Create NotificationViewModel.swfit under ViewModels folder.

When connectToHub() function is called, your app will be connected to Azure Notification Hub and ready to receive standard push notifications. But in order to receive notifications for Calls, you will have to register voip type deviceToken for ACS separately. We’ll cover this after we configure ACS connection in next section.

Connect to Azure Communication Services

Create CallingViewModel.swift under ViewModels folder.

This class handles all events related to receiving and starting calls. On init(), we initialize PKPushRegistry with voIP pushType and sets delegate to it self. This enables to receive push notifications in PKPushRegistryDelegate. Once we get push notifications, we have to report incoming call to CallKitManger.reportNewIncomingCall() that we have created earlier.

Add ACS and PushKit delegates into CallingViewModel as below.

Note that didUpdate delegate of pushRegistry stores updated deviceToken to self.voIPToken which we will use with ACS callAgent for pushNotification register in next section.

Register push notification

Now we are done with viewModels and ready to get some call notifications.

Add checkToken() function in ContentView.swift as below and initialize ACS callAgent class. Once callAgent is initialized, connect to notification hub using connectToHub() function in NotificationViewModel.swfit. With MSNotificationHubDelegate, we will receive didSave delegate event from notification hub and we are ready to register our voip token to ACS.

Change didSave function in NotificationViewModel.swift as below.

Look for initPushNotification() function in CallingViewModel.swift and find that this func is finally accessing self.voIPToken that was stored from didUpdate delegate of pushRegistry by calling self.callAgent?.registerPushNotifications(deviceToken: self.voIPToken, completionHandler: ((Error?) -> Void)!)

Well done!! we are ready to get voip call notifications now.

Views

Since we are done with viewModels, let’s tackle some views to actually make and receive a call.

But before we start drawing our views, we have to initialize our viewModels first. Open AzureCommunicationVideoCallingSampleApp.swift and modify the content as below. We will initialize viewModels we have created earlier and set them as environmentObject so that our child views can access them.

Because this sample also covers group call, we will create Grid layout view that will automatically resize each participant’s view size.

Create Grid.swift and GridLayout.swift(adopted from Stanford cs193p GridLayout.swift)

Create StreamView.swift for rendering video streams. This view will display remoteParticipants’s mic and camera status along with video stream and display name.

Create CallView.swift, DirectCall.swift, GroupCall.swift as below.

DirectCallView and GroupCallView preview

On direct call, which is 1:1, we are using DirectCallView which has local video and full screen remote video. On the other hand to direct call, we will use GroupCallView for GroupCall which will automatically resize views according to the participants number.

Now let’s change our HomeView.swift as below. It checks whether callAgent is initialized or not and prompt user to sign In if callAgent hasn’t been initialized.

Now we will create a few more views related to profile which include sign in and update profile(user id and tags for notification hub).

Create CommunicationsSettings.swift as below.

On CommunicationsSetting.swift, you can change your own token or displayName and signOut.

CommunicationsSetting.swift

Create TagsList.swift and TagRow.swift as below. This is need to manage tags for notification hub.

Create NotificationsSetting.swift as below. NotificationsSetting view is where you can set userId and manage tags to receive related notifications from hub.

NotificationsSetting.swift

Add ProfileCategory enums to Enums folder to navigate between Communications and Notifications settings. Modify Profile.swift as well.

Add SignInView.swift to handle signIn.

Add SheetType.swift enum to Enums folder. This enum will handle whether to show callview or signIn page.

And.. last… the ContentView!!!

Modify ContentView.swift as below.

Make sure the project build and everything looks ok. Run the project on real device. Change resouceName of AzureCommunicationVideoCallingSampleApp to “SecondUser” to deploy onto another device if you have one.

Call each other and see the notification wakes up the device even if it’s on lockscreen or app is terminated.

Thanks for reading this article. Integrating ACS and ANH all together at once was kinda heavy task especially there are not much of sample and documentation around.

Here is my github repository that has all the source code explained above.

Please be aware that this is more like POC and not Production ready as Azure Communication Services is not on GA yet as of Feb 19th 2021.

Hope you enjoyed my article and wish you had successfully run the application and make and receive some calls.

Thank you!

--

--

Responses (1)