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

  1. Start by creating a new iOS app using Xcode. Select Swift as a language for your app.
  2. 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 experience dylib loading failures.
  3. Find the ringback.wav and ringtone.wav audio files in Resources folder inside the SinchReferenceApp sample app, in the decompressed SDK folder, and add them to your app bundle.
  4. 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.
  5. 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 a Config.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'.
Copy
Copied
let APPLICATION_KEY = "..."
let APPLICATION_SECRET = "..."
let ENVIRONMENT_HOST = "..."

Sinch Client Mediator

Create a SinchClientMediator 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.
Copy
Copied
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 of SinchClientMediator, 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:).
Copy
Copied
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

In LoginViewController 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.
Copy
Copied
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 either CallKit or LiveCommunicationKit.
We'd love to hear from you!
Rate this content:
Still have a question?
 
Ask the community.