Getting started with Sinch In-app Calling for iOS SDK
This guide shows you how to get started integrating your iOS application with the In-app Calling SDK. Because we're just getting started, this guide only covers how to sign in to the In-app Calling SDK and how to make and receive calls.
Please, check our reference application for full implementation and additional functionalities, which is available on GitHub.
Prerequisites
- Xcode available here.
- In-app Calling SDK for iOS. In this guide, we're using the Swift SDK, but the Objective-C SDK is also available.
Upload your APNs signing keys
When a call is placed from UserA to UserB, the Sinch backend delivers a VoIP push notification via APNs to UserB to initiate the call.To allow Sinch to send push notifications on your behalf, you have to upload your APNs signing keys in your Sinch application configuration. You can find instructions on how to generate and upload your APNs signing keys here.
Set up the Xcode project
- Start by creating a new iOS app using Xcode. Select Swift as a language for your app.
- Download the Sinch Swift SDK from the SDK download page and decompress it. Add
SinchRTC.xcframework
folder to your project. Don't forget to embed the framework, or you'll experiencedylib
loading failures. - Find the
ringback.wav
andringtone.wav
audio files inResources
folder inside theSinchReferenceApp
sample app, in the decompressed SDK folder, and add them to your app bundle. - Enable "Voice over IP" Background Mode in the "Capabilities" menu of your app in order to integrate CallKit. If you skip this step, calls to the CallKit / LiveCommunicationKit component will fail.
- Add "Push Notifications" capability to your app. Without this capability, it won't be possible for the app to acquire a device token and receive notifications.
User registration
In order to place calls between two users, you must register both users on the Sinch backend within the application.
SinchClient Configuration
First, create aConfig.swift
file to store the credentials of your Sinch app on your dashboard to authenticate your SinchClient to the Sinch backend. Also set the environment host to base Sinch API URL. Default one is 'ocra.api.sinch.com'.let APPLICATION_KEY = "..."
let APPLICATION_SECRET = "..."
let ENVIRONMENT_HOST = "..."
Sinch Client Mediator
Create aSinchClientMediator
class, it will act as:- wrapper of
SinchClient
, root Sinch component, which provides access to features of Sinch SDK - delegate of
SinchClient
, for credential provisioning and monitoring of SinchClient status
SinchClientMediator
owns a SinchClient
object, and implements createAndStart(with:and:)
method that creates and starts its Sinch client. Note how
the completion callback is stored in a property, so it can be accessed later in the SinchClient
delegate callback.Note, you should use one instance of
SinchClientMediator
for your whole app.final class SinchClientMediator: NSObject {
private typealias ClientStartedCallback = (_ error: Error?) -> Void
private var clientStartedCallback: ClientStartedCallback!
var sinchClient: SinchClient?
func createAndStart(with userId: String,
and callback: @escaping (_ error: Error?) -> Void) {
do {
sinchClient = try SinchRTC.client(withApplicationKey: APPLICATION_KEY,
environmentHost: ENVIRONMENT_HOST,
userId: userId)
} catch let error as NSError {
// Report error.
callback(error)
}
clientStartedCallback = callback
guard let sinchClient = sinchClient else { return }
sinchClient.delegate = self
sinchClient.start()
}
}
Sinch Client Provisioning and Monitoring
Create an extension ofSinchClientMediator
, to conform with SinchClientDelegate
protocol, and implement credential provisioning and monitoring of SinchClient status.
Note, how stored copy of SinchClientMediator.clientStartedCallback
is used and reset in SinchClientDelegate.clientDidStart(_:)
and SinchClientDelegate.clientDidFail(_:error:)
.extension SinchClientMediator: SinchClientDelegate {
func clientRequiresRegistrationCredentials(_ client: SinchRTC.SinchClient,
withCallback callback:
SinchRTC.SinchClientRegistration) {
do {
// WARNING: test implementation to create JWT token,
// shouldn't be used for production application.
let jwt = try SinchJWT
.sinchJWTForUserRegistration(withApplicationKey: APPLICATION_KEY,
applicationSecret: APPLICATION_SECRET,
userId: client.userId)
callback.register(withJWT: jwt)
} catch {
callback.registerDidFail(error: error)
}
}
func clientDidStart(_ client: SinchClient) {
guard clientStartedCallback != nil else { return }
clientStartedCallback(nil)
clientStartedCallback = nil
}
func clientDidFail(_ client: SinchClient, error: Error) {
guard clientStartedCallback != nil else { return }
clientStartedCallback(error)
clientStartedCallback = nil
}
}
Note:
Creation of JWT token is required to authenticate SinchClient (see
SinchClient
docs). To simplify this tutorial, the token is created locally in the app. This is bad security practice, as it stores the application secret in your code. In production application the generation of the JWT should be delegated to your backend. For the implementation of SinchJWT.sinchJWTForUserRegistration(withApplicationKey:applicationSecret:userId:)
, please refer to SinchJWT.swift
file in the sample app, bundled together with Swift Sinch SDK.User login
InLoginViewController
using Connection Inspector view, connect outlets (UITextField
for username) and login action. Inside login action invoke SinchClient creation with provided username, using client mediator instance SinchClientMediator
.See,
UIViewController+Presentation
and UIViewController+Alert
extensions in sample application, for view controller and alert creation implementation.final class LoginViewController: UIViewController {
...
var sinchClientMediator: SinchClientMediator?
@IBAction private func login(_ sender: Any) {
let name = userNameTextField?.text ?? ""
// SinchClient registration for specific user.
sinchClientMediator?.createAndStart(with: name) { [weak self] error in
guard let self = self else { return }
if (error != nil) {
// Report error.
} else {
// Hide keyboard.
self.userNameTextField.resignFirstResponder()
// If success, transfers to the next screen, to make a call. Note,
// in Storyboard for MainViewController's Storyboard ID should be set as 'main'.
let mainViewController: MainViewController =
self.prepareViewController(identifier: "main")
mainViewController.userName = name
self.present(mainViewController, animated: true, completion: nil)
}
}
}
}
Next steps
Now that your application is created, you can configure application to make and receive a call with eitherCallKit
or LiveCommunicationKit
.