Signed Call iOS SDK

Learn how to integrate Signed Call iOS SDK in your app to avail the Signed Call feature.

Overview

CleverTap provides in-app calls via its Signed Call iOS SDK, which means you can make and receive calls in any iOS application if the device has an internet connection and Signed Call iOS SDK. This section shows you how to set up and integrate the Signed Call iOS SDK and manage calls. To know more about the Signed Call feature, refer to Signed Call.


The Signed Call framework is built using Swift-5 in Xcode v16. To support CallKit, the target iOS version for deployment must be greater than or equal to iOS 12. You can test Signed Call on both devices and simulators.

πŸ“˜

Simulator Support

The Signed Call iOS SDK does not support testing on simulators because CallKit is not supported in the simulator.

Setup

This section explains how to set up the Signed Call iOS SDK. Following is the setup required before you start integrating the Signed Call iOS SDK:

Enable VoIP Push

The following is a list of required details to enable your infrastructure with VoIP push:

  • Team ID
  • Bundle ID
  • Authkey .p8 file
  • .p12 VoIP certificate
  • .pem VoIP certificate
  • Key ID

To know more, refer to VoIP APNs Setup.

Install Signed Call iOS SDK using Pods

To install the Signed Call iOS SDK:

  1. Add the pod spec repo as a source and the CleverTap-SignedCall-SDK pod to your Podfile as shown below:
source 'https://github.com/CleverTap/podspecs.git'
source 'https://github.com/CocoaPods/Specs.git'

target 'SignedCallDemo' do
  use_frameworks!
  pod 'CleverTap-SignedCall-SDK'

end

post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
        		config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
            config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
   end
end
  1. Update your Podfile, and run pod install --repo-update in your terminal.
    For more details, refer to Pod setup.

Set Up Xcode Project

To set up your Xcode project, add the following capabilities to your project:

Add Permissions

To add permissions in your application's Info.plist file:

  1. Navigate to the Info.plist file from your project navigator.
2782

Information Property List in Info.plist File

  1. Create the Privacy - Camera Usage Description key of string type.
  2. Create the Privacy - Microphone Usage Description key of string type.

To know more, refer to Requesting Access to Protected Resources.

Disable Bitcode

To disable bitcode from your build settings:

  1. Click the Build Setting tab.
  2. Search Enable Bitcode.
  3. Select No to disable it.
Build Options in Build Settings

Build Options in Build Settings

Set Up Signing & Capabilities

Add the following capabilities from the Signing & Capabilities tab:

  • Add Push Notifications capability.
  • Select the following modes under the Background Modes capability:
    • Audio, Airplay, and Picture in Picture
    • Voice over IP
Set Up Signing & Capabilities

Set Up Signing & Capabilities

Set Up an Outgoing Tone

Add the .mp3 file named outgoing_tone to your project to set up an outgoing tone. This file plays the added outgoing tone when the user makes a call.

Configure Quick Launch Button on the CallKit Screen

The CallKit function adds a quick launch button on the call screen for your application, which helps to switch between the application and the native CallKit screen. The icon file (white mask) SCCallkitLogo.png is read from your application resources.

πŸ“˜

Icon Image File Specifications

The icon must be a square image with a side length of 40 points. The alpha channel of the image creates a white mask image used in the native CallKit screen, which helps to switch between the native CallKit screen and the application calling screen.

Integrate CleverTap iOS SDK

The Signed Call iOS SDK uses CleverTap SDK for analytics. Signed Call iOS SDK requires an active CleverTap instance as a parameter during the SDK initialization. If the CleverTap instance is unavailable, the Signed Call iOS SDK does not initialize and returns an error ERR_CLEVERTAP_URL_NOT_AVAILABLE.

To integrate the CleverTap iOS SDK, refer to the CleverTap iOS Integration Guide.

πŸ“˜

Minimum Supported Version

The Signed Call iOS SDK requires a CleverTap SDK version of v4.1.0 or higher.

Integrate the Signed Call iOS SDK

After the CleverTap iOS SDK is integrated, register and initialize your application with the SignedCallSDK framework as follows:

  1. Open your AppDelegate file and import both, CleverTap and Signed Call SDKs as shown below:
import CleverTapSDK
import SignedCallSDK
#import <CleverTapSDK/CleverTap.h>
#import <SignedCallSDK/SignedCallSDK-Swift.h>
  1. Enable SignedCallSDK logging as follows:
SignedCall.isLoggingEnabled = true
[SignedCall setIsLoggingEnabled: YES];
  1. Call the registerVoIP function to generate a VoIP token and to set pushRegistryDelegate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        CleverTap.setDebugLevel(CleverTapLogLevel.off.rawValue)
        CleverTap.autoIntegrate()
        SignedCall.isLoggingEnabled = true
        SignedCall.cleverTapInstance = CleverTap.sharedInstance()
        
        SignedCall.registerVoIP()
        SignedCall.rootViewController = self.window?.rootViewController
        return true
    }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [CleverTap setDebugLevel: CleverTapLogOff];
    [CleverTap autoIntegrate];
    
    [SignedCall setIsLoggingEnabled: YES];
    [SignedCall registerVoIPWithAppName:@"TestApp"];
    SignedCall.rootViewController = self.window.rootViewController;
    
    return YES;
}

If SceneDelegate is used then set the rootViewController inside willConnectToSession function, once rootViewController value is available.

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
   guard let windowScene = (scene as? UIWindowScene) else { return }
   let window = windowScene.windows.first
   SignedCall.registerVoIP()
   SignedCall.rootViewController = self.window?.rootViewController
}
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
		[SignedCall registerVoIPWithAppName:@"TestApp"];
    SignedCall.rootViewController = self.window.rootViewController;
}

The registerVoIP function expects the following parameters:

ParameterDescriptionTypeNotes
rootViewThe view controller on which the call screen displays.UIViewControllerRequired
appNameThe application name you want to display on the CallKit incoming screen.StringOptional
  1. Initialize the Signed Call iOS SDK as follows:
SignedCall.initSDK(withInitOptions: initOptions) { result in
    switch result {
    case .success(let success):
        print("SDK Initialized! \(success)")
        //Handle success scenario
        
    case .failure(let error):
        print("SDK initialization failed \(error)")
        //Handle failure scenario
    }
}
[SignedCall initSDKWithInitOptions:initOptions completion:^(BOOL success, SCErrorObj * _Nullable error) {
      NSLog(@"%i", success);
      NSLog(@"%@", error);
}];

The syntax for the parameters of initOptions is as follows:

let initOptions: [String: Any] = [
    "accountID": "Signed Call Account Id",
    "apiKey": "Signed Call Api Key",
    "cuid" : "unique-cuid",
    "production": true/false
]
NSDictionary *initOptions = @{
    @"accountID": @"Signed Call Account Id",
    @"apiKey": @"Signed Call Api Key",
    @"production": @0/ @1,
    @"cuid": @"unique-cuid"
    
};

The initOptions in the function call expects a dictionary with the following parameters:

Parameter

Description

Type

Notes

accountID

  • Unique identity of the client's account.
  • Available from the CleverTap dashboard.

String

Required

apiKey

  • Unique identity of the client's account.
  • Available from the CleverTap dashboard.
StringRequired
cuidUnique identity of the user.StringRequired
productionThe Signed Call iOS SDK provides production and development environments to enable the VoIP push.
  • production is used for testing VoIP push after deploying the app on TestFlight or the App Store.
  • development is used for testing VoIP push during the development phase on a simulator or device.
Note: Remember to set production to true when deploying the app on production and false for development builds.
BooleanRequired

πŸ“˜

CUID Validation Rules

The following are the validation rules for cuid:

  • Must range between 5 and 50 characters, starting from v0.0.6; otherwise, it should be less than 15 characters.
  • Must start with either alphabet or number.
  • The name is case-sensitive, and only '_' is allowed as a special character.
  • The cuid parameter cannot be of type number-number, that is, a number followed by a special character, which is again followed by another number. For example, org_25 is allowed, but 91_8899555 is not permitted.
  • Must be unique for every user.
  • Must be unique for every device to allow multiple logins for the user from different devices. In such cases, the user will have multiple cuid's.

Make a Signed Call

Use the following code to make a Signed Call:

let customMetaData = SCCustomMetadata(remoteContext: String, initiatorImage: String, receiverImage: String)

let callOptions = SCCallOptionsModel(context: String, receiverCuid: String, customMetaData: SCCustomMetadata)


SignedCall.call(callOptions: callOptions) { result in
            switch result {
            case .success(let success):
                //Handle call initiated
                
            case .failure(let error):
                //Handle call failure
            }
        }
SCCustomMetadata *customMetaData = [[SCCustomMetadata alloc] initWithRemoteContext:@"string context" initiatorImage:@"image string url" receiverImage:@"image string url"];

SCCallOptionsModel *model = [[SCCallOptionsModel alloc] initWithContext:@"context string" receiverCuid:@"cuid string" customMetaData: customMetaData];

[SignedCall callWithCallOptions:model completion:^(BOOL success, SCErrorObj * _Nullable error) {
    NSLog(@"%i", success);
    NSLog(@"%@", error);
}];

The parameters to make a Signed Call are as follows:

Parameter

Description

Type

Notes

cuid

It is the receiver's cuid.

String

Required

context

It specifies the context of the call. For example, the Delivery Partner is calling, the Driver is calling, the Agent is calling, and so on.

Note: It must include alphanumeric characters, and the length must not exceed 64 characters

String

Required

customMetaData

It is a SCCustomMetadata object with the following properties:
  • remote_context (string): Specifies the call context to be displayed to the receiver if passed. This property is optional.
  • receiverImage (string): URL that displays the receiver's image to the initiator of the call. This property is optional.
  • initiatorImage (string): URL that displays the initiator's image to the receiver of the call. This property is optional.
object of SCCustomMetadata
class
Optional

Handle Call Events

Add the following code inside the viewDidLoad() of your View Controller to monitor call events:

NotificationCenter.default.addObserver(self, selector: #selector(self.callStatus(notification:)), name: SCCallStatusDidUpdate, object: nil)
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(receiveCallNotifications:) name:@"SCCallStatusDidUpdate" object:nil];

Following is an example of creating a function to handle call events:

@objc func callStatus(notification: Notification) {
  let callDetails = notification.userInfo?["callDetails"] as? SCCallStatusDetails
  
  let status = callDetails?.status
  let callDirection = callDetails?.callDirection
  let calleeCuid = callDetails?.callDetails.calleeCuid ?? ""
  let callerCuid = callDetails?.callDetails.callerCuid ?? ""
  let context = callDetails?.callDetails.context
  let initiatorImage = callDetails?.callDetails.initiatorImage
  let receiverImage = callDetails?.callDetails.receiverImage

    if callDirection == .OUTGOING {
      //Handle events for initiator of the call
      switch status {
      case .CALL_DECLINED_DUE_TO_LOGGED_OUT_CUID:
          print("When the receiver's cuid is logged out and logged in wit  different cuid")
      case .CALLEE_MICROPHONE_PERMISSION_NOT_GRANTED:
          print("When the Microphone permission is denied or blocked whil  receiver answers the call")
      case .CALL_IS_PLACED:
          print("When the call is successfully placed")
      case .CALL_CANCELLED:
          print("When the call is cancelled from the initiator's end")
      case .CALL_DECLINED:
          print("When the call is declined from the receiver's end")
      case .CALL_MISSED:
          print("When the call is missed at the receiver's end")
      case .CALL_ANSWERED:
          print("When the call is picked up by the receiver")
      case .CALL_IN_PROGRESS:
          print("When the connection to the receiver is established")
      case .CALL_OVER:
          print("When the call has been disconnected")
      case .CALLEE_BUSY_ON_ANOTHER_CALL:
          print("When the receiver is busy on another call")
      default: break
      }
  } else if callDirection == .INCOMING {
      //Handle events for receiver of the call
      // Receiver will get the same list of events
  }
}
- (void) receiveCallNotifications:(NSNotification *) notification {
  NSLog(@"%@", notification.userInfo[@"callStatus"]);
}

Close Socket Connection

The Signed Call iOS SDK uses the socket connection to signal VoIP calls from the initiator to the receiver. After successful SDK initialization, the socket connection to initiate or receive VoIP calls opens.
If the socket is left open for a longer period, the application might drain the device's battery. Therefore, we recommend disconnecting the socket after all expected/pending transactions are over.
To close the socket connection, use the following method as per your business use case:

SignedCall.disconnectSignallingSocket()
[SignedCall disconnectSignallingSocket];

The following is the Signed Call iOS SDK behavior after the SDK calls the disconnectSignallingSocket() method:

FunctionalitySigned Call iOS SDK Behavior
Initiate a callUsers cannot initiate calls. Signed Call iOS SDK returns ERR_SIGNALLING_SOCKET_CONNECTION failure if they attempt a VoIP call request. It is essential to reinitialize the Signed Call SDK if a use case arises where a call needs to be initiated.
For example, if a user places an order in the application and the business wants to give the option to initiate a VoIP call, the Signed Call iOS SDK needs to be reinitialized.
Receive a callUsers can still receive calls as Signed Call uses APNs as a fallback channel to receive VoIP calls.

Busy Handling

The following scenarios describe the Signed Call iOS SDK behavior when the user is busy on a call:

Scenario 1: The user is busy on a call (VoIP or PSTN), and another user initiates a VoIP call with the user who is busy on another call. In this case, the Signed Call iOS SDK displays User is busy on another call on the outgoing call screen and declines the initiated call.

Scenario 2: The user is busy on a Signed Call VoIP call and receives another VoIP or PSTN call. In this case, the Signed Call iOS SDK provides the option of either declining the new call or ending the current call and accepting the new call.

πŸ“˜

Put a Call on Hold

Currently, Signed Call iOS SDK does not support putting the call on hold functionality.

Call Hangup Functionality

The hangup function ends a call for both parties programmatically. For example, if there is a metered call and the business wants to end the call after a specific duration, then they must maintain a timer in the application and call the hangup function at the appropriate time.

SignedCall.hangup()
[SignedCall hangup];

Override the Dashboard Branding for Call Screen

CleverTap dashboard provides a branding tool to alter the look and feel of the call screens. If you have multiple applications to integrate with the Signed Call iOS SDK, all those applications will share the same branding that you have set from the CleverTap dashboard. By overriding the dashboard's call screen branding, you can have different branding for each application.

To override the dashboard branding, use overrideDefaultBranding during the Signed Call iOS SDK initialization.

SignedCall.overrideDefaultBranding = SCCallScreenBranding(bgColor: "bgColor", fontColor: "fontColor", logo: "logoUrl", buttonTheme: ButtonTheme)
SCCallScreenBranding *branding = [[SCCallScreenBranding alloc] initWithBgColor:@"bgColor" fontColor:@"fontColor" logo:@"logo" buttonTheme: ButtonThemeLight/ ButtonThemeDark];

SignedCall.overrideDefaultBranding = branding;

The parameters to override the dashboard's call screen branding are as follows:

ParameterDescriptionTypeNotes
bgColorHex color code for the background of the call screens. For example, #000000.StringRequired
fontColorHex color code for the text displayed on the call screens. For example, #ffffff.StringRequired
logoThe HTTPS URL of the image that renders in the call screens.StingRequired
buttonThemeThe theme for the control buttons of the call screen (Mute, Speaker, and Bluetooth).
Note: The .light theme represents the white color of the buttons, whereas the .dark is for black color.
ButtonThemeRequired

Logout the Signed Call iOS SDK

Add the following code to clear the session after a user logs out from the application. It ends all the connections, and to make a new call, you must repeat the Initialization and Authentication steps.

SignedCall.logout()
[SignedCall logout];

Exceptions

From iOS 13, Apple now mandates that all VoIP push notifications must be reported to the CallKit framework as a new call. If a VoIP push notification is not reported to CallKit within the required time window, iOS terminates the application. If VoIP push notifications are not reported to CallKit repeatedly, Apple ultimately stops delivering VoIP push notifications to the application. The end user needs to reinstall the application to get VoIP push notifications again.
Due to this, the SignedCallSDK demonstrates the following two expected behaviors in iOS:

  • If the receiver is busy in an ongoing VoIP call, then making another VoIP call to the same receiver reports an incoming dummy call to CallKit and ends it instantly but does not affect the previous, ongoing call.
  • If the user has logged out from the active session maintained by SignedCallSDK by calling the SignedCall.logout(), then making a call to the same cuid opens up the CallKit screen and ends it on the next tick as an invalid call.

To know more, refer to Apple pushRegistry

Errors

The following table lists the different errors and their probable causes:

ErrorDescription
ERR_NETWORK_NOT_AVAILABLENo internet connection.
ERR_SIGNEDCALLSDK_NOT_INITIALIZEDSigned Call iOS SDK is not initialized.
ERR_MICROPHONE_PERMISSION_NOT_GRANTEDMicrophone permission not granted.
ERR_CONTACT_NOT_REACHABLEThe receiver is not reachable.
ERR_SERVER_FAILUREThe server is not reachable.
ERR_INVALID_CUIDInvalid cuid.
ERR_CUID_ALREADY_CONNECTED_ELSEWHEREThe cuid is connected to another device.
ERR_VOIP_SERVICE_FAILED_TO_REGISTERThe VoIP service failed to register.
ERR_CUID_MISSINGThe cuid is missing.
ERR_CONTACT_REGISTRATION_FAILEDContact registration failed.
ERR_ACCOUNTID_REQUIREDThe Signed Call Account ID is required.
ERR_APIKEY_REQUIREDThe API Key is required.
ERR_INVALID_LENGTH_CUIDThe cuid length must be in the range of 5-50.
ERR_PRODUCTION_FIELD_REQUIREDThe Production key is missing.
ERR_CLEVERTAP_INSTANCE_REQUIREDCleverTap instance not available.
ERR_STOP_RETRYSigned Call iOS SDK initialization failed.
ERR_FAILURE_IN_MAKE_CALLFailure while making a call.
ERR_CALL_CONTEXT_INVALIDThe characters are not alphanumeric, or the length is more than 64 characters.
ERR_CAN_NOT_CALL_SELFThe receiver's and initiator's cuid cannot be the same.
ERR_CLEVERTAP_URL_NOT_AVAILABLEThe CleverTap iOS SDK's base URL was not found.
ERR_SIGNALLING_SOCKET_CONNECTIONConnection to a socket signaling channel is not available.

FAQs

Q. Is Signed Call accountId and apiKey the same as CleverTap's accountId and token?

A. No. Signed Call accountId and apiKey differ from CleverTap's accountId and token. You can find these details under your dashboard's Signed Call Settings.

Q. Why are SignedCallSDK dependencies not downloaded even after running the pod install?

A. Performing pod install --repo-update will help download and install the required latest dependencies.

Q. What channels are used for call routing by Signed Call iOS SDK?

A. Signed Call iOS SDK uses an active socket connection when the SDK is initialized. The socket connection is a primary routing channel to receive the calls, whereas APNs is a fallback channel in case the receiver is not connected to the socket channel. This socket connection processes the call requests raised to make a call. For more information, refer to the Best practices for initializing Signed Call SDKs.

Q: What causes VoIP test calls to fail when the app is in the background or has been terminated?

A: To test VoIP calls in the background and killed state, you must set up the Dashboard Mobile Push settings respective to the application's production value in initOptions. If you set "production" value in initOptions to false, then set up APNs push mode in Dashboard to Development for VoIP calls to work in debug mode. Also setup APS Environment in entitlements file to development.
If you set "production" value in initOptions to true, then setup APNs push mode in Dashboard to Production for VoIP calls to work in release mode or Testflight build.