Signed Call React Native for M2P Campaigns

Learn how to integrate Signed Call React Native SDK in your application to avail the Signed Call Machine-to-Person (M2P) feature.

Overview

CleverTap allows In-App Machine-to-Person (M2P) campaign calls via the Signed Call React Native SDK, enabling you to receive calls in any React Native application if the device has an internet connection and Signed Call React Native SDK. This document provides information about:

  • Signed Call React Native SDK integration
  • Managing Signed Calls from your React Native application

For more information about Signed Call, refer to Signed Call.

Prerequisites

The prerequisites for the integration vary depending on the platforms:

For Android Platform

Here are the requirements for integrating the Signed Call React Native SDK into the Android platform:

  • SDK version 21 and above
  • Java version 8 and above
  • Application permissions for the following:

πŸ“˜

iOS Platform

CleverTap will soon start iOS Platform Support for M2P campaigns.

Integrate Signed Call React Native SDK

There are four major steps for integrating Signed Call React Native SDK:

Add CleverTap React Native Package to Project

To integrate the Signed Call React Native SDK, add the CleverTap React Native SDK/Package to your project using Yarn or NPM as shown below:

yarn add @clevertap/[email protected]
npm install @clevertap/[email protected]

Set Up Signed Call Android SDKs

To set up the Signed Call Android SDK, follow these steps:

  1. Include mavenCentral in your project-level build.gradle file as follows:
allprojects {
    repositories {
        mavenCentral()
    }
}
  1. Add the following code to the dependencies element of the build.gradle file of your application module:
//To integrate Signed Call Android SDK,
implementation "com.clevertap.android:clevertap-signedcall-sdk:0.0.6.2-m2p-beta"

//To enable the socket-based signaling channel
implementation('io.socket:socket.io-client:2.1.0') {
        exclude group: 'org.json', module: 'json'
} 

//To load the image assets on the call screens
implementation 'com.github.bumptech.glide:glide:4.12.0'

//To process the incoming call push for the receiver
implementation 'androidx.work:work-runtime:2.7.1'

//To build a responsive UI for the call screens
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

The Signed Call Android SDK uses CleverTap Android SDK for analytics. This requires an active CleverTap instance as a parameter during the SDK initialization. To integrate the CleverTap Android SDK, refer to CleverTap Android SDK Integration.

πŸ“˜

Signed Call React Native SDK Compatibility

The Signed Call React Native SDK v0.0.6-m2p.2 is compatible with Signed Call Android SDK v0.0.6.2-m2p-beta or higher and CleverTap Android SDK v6.2.0 or higher.

The Signed Call Android SDK uses FCM dependency to fetch the device FCM token required for successful SDK initialization. The Signed Call then uses this FCM token to enable calls via the FCM-based call routing channel.

  1. Add the following code to include the FCM dependency in the application module's dependency element:
implementation 'com.google.firebase:firebase-messaging:21.0.0'

πŸ“˜

FCM Version

The minimum supported version of FCM must be v21.0.0 or higher to integrate with your Android platform.

Initialize Signed Call React Native SDK

To initialize Signed Call React Native SDK in your JavaScript or TypeScript code, call the init method on the SignedCall reference as shown below:

static initialize(initProperties: object): Promise<SignedCallResponse>

This method returns a Promise object. To get the results, use the then() method as follows:

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      const error = response.error;
      const errorCode = error?.errorCode;
      const errorMessage = error?.errorMessage;
      const errorDescription = error?.errorDescription;
      console.log(
            'Signed Call initialization failed: \n' +
            'error-code: ' + errorCode + '\n' +
            'error-message: ' + errorMessage + '\n' +
            'error-description: ' + errorDescription
      );
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      const error = response.error;
      const errorCode = error?.errorCode;
      const errorMessage = error?.errorMessage;
      const errorDescription = error?.errorDescription;
      console.log(
            'Signed Call initialization failed: \n' +
            'error-code: ' + errorCode + '\n' +
            'error-message: ' + errorMessage + '\n' +
            'error-description: ' + errorDescription
      );
    }
  })
  .catch(e => {
    console.error(e);
  });

The initProperties is a Map object with the following properties:

PropertiesDescriptionTypeComments
accountIdThe unique identity of the client account. It is available from the CleverTap dashboard.StringRequired
apiKeyThe unique identity of the client's account. It is available from the CleverTap dashboard.StringRequired
cuidThe unique identity of the user.StringRequired
m2pConfigurationIt configures the content of the foreground notification, which SDK uses to preprocess the received campaign calls.

For more information, refer to Configure Machine-to-Person (M2P) Feature.
ObjectRequired
missedCallActions
  • It configures the action buttons for the missed call notification.
  • No action buttons are displayed on a missed call notification without this parameter.
  • A maximum of three action buttons can be configured for the missed call notification, where each entry in the map object represents an action button.
For more information, refer to missedCallActions.
ObjectOptional
promptReceiverReadPhoneStatePermissionWhen the receiver answers the call, it prompts the receiver with Read Phone State permission.
The SDK uses Read Phone State permission to enable busy handling for PSTN calls. The default value is false.

For more information, refer to Read Phone State.
BooleanOptional
promptPushPrimerIt enables the Push Primer to support Android 13 changes for the Runtime Notification Permission.

For more information, refer to Android 13 Changes.
ObjectOptional
notificationPermissionRequiredIt indicates whether notification permission is required for the SDK initialization on Android 13 and onwards.

The default value is true.

For more information, refer to its usage.
BooleanOptional
overrideDefaultBrandingIt overrides the call screen branding set from the dashboard. The default branding is the one you set from the dashboard.

For more, refer to its usage.
ObjectOptional

πŸ“˜

CUID Validation Rules

The following are the validation rules for cuid:

  • The characters must range between 5 to 50. For earlier SDK versions, limit characters to less than 15.
  • Start with either alphabet or a number.
  • The name is case-sensitive, and only '_' is allowed as a special character.
  • Cannot be of type number-number, i.e. 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.

The syntax for initProperties is as follows:

import { Platform } from 'react-native';

let initProperties: { [k: string]: any } = {
      accountId: <string / required>,
      apiKey: <string / required>,
      cuid: <string / required>,
  		promptReceiverReadPhoneStatePermission: <boolean / optional>,
  		promptPushPrimer: <object / optional>,
  		notificationPermissionRequired: <boolean / optional>,
  		overrideDefaultBranding: <object / optional>,
  		missedCallActions = <object / optional>,
}
import { Platform } from 'react-native';

let initProperties = {
      accountId: <string / required>,
      cuid: <string / required>,
  		promptReceiverReadPhoneStatePermission: <boolean / optional>,
  		promptPushPrimer: <object / optional>,
  		notificationPermissionRequired: <boolean / optional>,
  		overrideDefaultBranding: <object / optional>,
  		missedCallActions = <object / optional>,
}

Configure Machine-to-Person (M2P) Feature

The Signed Call React Native SDK runs a foreground service on the Android platform to communicate with the server before the actual campaign call and fetch information about the campaign meta and flow. During this process, the SDK displays a foreground notification to the user. After processing, the SDK replaces the foreground notification with the incoming call notification.

πŸ“˜

Note

The foreground service keeps the application in the wake state, reducing the chances of communication failures due to network or device restrictions imposed by the Android OS or OEM.

To configure the foreground notification, use the m2pConfiguration parameter of the object type inside the initProperties as follows.

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let m2pConfiguration = {
  title: '<title>',    // Required
  subTitle: '<subTitle>',  // Required
  cancelCtaLabel: '<cancelCtaLabel>',  // Optional
  largeIcon: '<resource_name_in_android_drawable_folder>",   // Optional
};

let initProperties = {
  ....
  m2pConfiguration: m2pConfiguration,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
 })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let m2pConfiguration = {
  title: '<title>',    // Required
  subTitle: '<subTitle>',  // Required
  cancelCtaLabel: '<cancelCtaLabel>',  // Optional
  largeIcon: '<resource_name_in_android_drawable_folder>",   // Optional
};

let initProperties = {
  ....
  m2pConfiguration: m2pConfiguration,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

The following table provides information about the parameters used in the m2pConfiguration object:

Method NameDescriptionTypeRequired/Optional
titleDenotes the title text. The maximum character limit is 65 characters.StringRequired
subtitleDenotes the subtitle text. The maximum character limit is 240 characters.StringRequired
largeIconDenotes the name of the drawable resource under android/app/src/res/drawable folder.StringOptional
cancelCtaLabelServes as an alternative for manual dismissal of the notification, ensuring users have an option if it does not disappear automatically.StringOptional

overrideDefaultBranding

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 SDK, all those applications will share the same branding you have set from the CleverTap dashboard. By overriding the dashboard's call screen branding, you can have different branding for each application.

Use an optional overrideDefaultBranding parameter of the object type inside the initProperties to override the dashboard branding for call screens.

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let callScreenBranding = {
  bgColor: '<hex color code>',    //The background color of the call screens
  fontColor: '<hex color code>',  //The color of the text displayed on the call screens
  logoUrl: '<https url>',         //The image URL that renders on the call screens.
  buttonTheme: 'light' or "dark", //The theme of the control buttons shown on the ongoing call screen(i.e. Mute, Speaker and Bluetooth)
};

let initProperties = {
  ....
  overrideDefaultBranding: callScreenBranding,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
 })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let callScreenBranding = {
  bgColor: '<hex color code>',    //The background color of the call screens
  fontColor: '<hex color code>',  //The color of the text displayed on the call screens
  logoUrl: '<https url>',         //The image URL that renders on the call screens.
  buttonTheme: 'light' or "dark", //The theme of the control buttons shown on the ongoing call screen(i.e. Mute, Speaker and Bluetooth)
};

let initProperties = {
  ....
  overrideDefaultBranding: callScreenBranding,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

Manage Permission

The following permissions are required for the Signed Call React Native SDK integration:

Read Phone State

This is an optional permission. The Signed Call React Native SDK uses this permission to enable busy handling for Public Switched Telephone Network (PSTN) calls. This permission determines if the receiver is available or engaged on a PSTN call. We recommend you add the required handling to request the Read Phone State permission before initiating a call.

Use the promptReceiverReadPhoneStatePermission parameter of the boolean type inside the initProperties as shown below, allow the Signed Call React Native SDK to prompt the read phone state permission at the receiver's end when the receiver answers the call.

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptReceiverReadPhoneStatePermission: true/false,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptReceiverReadPhoneStatePermission: true/false,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

Notification Permission

This is a required permission. All applications running on Android 13 and above must request Runtime Notification Permission from the user before sending notifications.

For the Android platform, the Signed Call React Native SDK utilizes both local and remote notifications during VoIP calls. Therefore, notification permission is required from the user to initialize the Signed Call Flutter SDK.

Push Primer for Push Notification Permission

The Push Primer is a local In-App notification that educates users about the context of the notification before requesting permission.

To initialize the Signed Call React Native SDK for Android 13 and above, you can enable the Push Primer using any of the following:

Enable Push Primer via CleverTap React Native SDK

CleverTap React Native SDK v1.0.0 and above supports Push Primer. For more information, refer to CleverTap React Native Push Primer.

Enable Push Primer via Signed Call React Native SDK

The Signed Call React Native SDK enables you to display Push Primer using an optional promptPushPrimer parameter of Object type inside the initProperties. It ensures that the initialization happens after the notification permission is granted using Push Primer.

To configure the Push Primer:

  1. Create a Push Primer configuration using the In-App campaign's Half-Interstitial or Alert template.
//Creates push primer config using Half-Interstitial template
const pushPrimerConfig = {
  inAppType: 'half-interstitial',
  titleText: 'Get Notified',
  messageText:'Please enable notifications on your device to use Push Notifications.',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  backgroundColor: '#FFFFFF',
  btnBorderColor: '#0000FF',
  titleTextColor: '#0000FF',
  messageTextColor: '#000000',
  btnTextColor: '#FFFFFF',
  btnBackgroundColor: '#0000FF',
  btnBorderRadius: '2',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};

//Creates push primer config using Alert template
const pushPrimerConfig = {
  inAppType: 'alert',
  titleText: 'Get Notified',
  messageText: 'Enable Notification permission',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};
//Creates push primer config using Half-Interstitial template
const pushPrimerConfig = {
  inAppType: 'half-interstitial',
  titleText: 'Get Notified',
  messageText:'Please enable notifications on your device to use Push Notifications.',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  backgroundColor: '#FFFFFF',
  btnBorderColor: '#0000FF',
  titleTextColor: '#0000FF',
  messageTextColor: '#000000',
  btnTextColor: '#FFFFFF',
  btnBackgroundColor: '#0000FF',
  btnBorderRadius: '2',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};

//Creates push primer config using Alert template
const pushPrimerConfig = {
  inAppType: 'alert',
  titleText: 'Get Notified',
  messageText: 'Enable Notification permission',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};
  1. Pass the Push Primer configuration inside the promptPushPrimer parameter of the initProperties. It displays the Push Primer during the SDK initialization.
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptPushPrimer: pushPrimerConfig,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptPushPrimer: pushPrimerConfig,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

πŸ“˜

Note

  • The above configuration enables the Push Primer only if the device and application both target Android 13 (API level 33) or higher.
  • During the SDK initialization, Signed Call React Native SDK registers a listener to obtain the result of the push notification permission request. After registration, this listener continues monitoring the permission result, even if the Push Primer prompt is displayed from the CleverTap Flutter SDK.
  • If the notification permission is denied, the Signed Call React Native SDK returns an exception within the promise object that is associated to the SignedCall.initialize(..) method.

Configure Notification Permission as Optional

πŸ“˜

Expected SDK Behaviour without Notification Permission

  • Avoid making notification permissions optional. Without this permission, the SDK can only display the call screen on Android 13 and above when the app is in the foreground. Otherwise, incoming calls are automatically declined, triggering the CallStatus.DeclinedDueToNotificationsDisabled event in the SignedCall.SignedCallOnCallStatusChanged listener.
  • If you decide to set notification permissions as optional, implementing the SignedCall.SignedCallOnCallStatusChanged listener is essential.

Starting with Android 13, the Signed Call React Native SDK requires notification permission to display call notifications, allowing users to interact with and return to calls.

By default, the SDK needs this permission for initialization. If it is not granted, the SDK returns an exception within the promise object linked to the SignedCall.initialize(..) method.

To make notification permission optional during SDK initialization, set the notificationPermissionRequired parameter of the initProperties to false, as shown below:

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  notificationPermissionRequired: <true/false>,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  notificationPermissionRequired: <true/false>,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

Log Out Signed Call React Native SDK

When the Signed Call React Native SDK initializes, the init configuration is maintained in a local session. Use the logout() method to invalidate the active session and disable the Signed Call functionality (receiving the M2P campaigns). To enable it again, repeat the steps listed under Initialize Signed Call React Native SDK.

SignedCall.logout();
SignedCall.logout();

Receive an M2P Campaign Call

Signed Call uses the FCM routing channel to receive M2P campaign calls at the receiver's end:

πŸ“˜

FCM Version

The minimum supported version of FCM must be v21.0.0 or higher to integrate with your Android platform.

To enable the FCM channel, follow these steps:

  1. Add your FCM Server Key to the Signed Call section of the CleverTap dashboard. Ignore this step if you have already added it.
  2. Allow CleverTap Android SDK to process the FCM push of VoIP call by adding the following entries to your AndroidManifest.xml file.
<application>
         ....
         ....
        <service android:name="com.clevertap.android.sdk.pushnotification.fcm.FcmMessageListenerService"
                 android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        ....  
 </application>

  1. Add the following code to your Application class:
CleverTapAPI.setSignedCallNotificationHandler(new SignedCallNotificationHandler());
CleverTapAPI.setSignedCallNotificationHandler(SignedCallNotificationHandler())

The setup for campaign calls via the FCM channel is now complete.

Handle Call Events (All Platforms)

To define custom handling for call-related events, you must register the SignedCall.SignedCallOnCallStatusChanged listener. This listener provides an object - CallStatusDetails containing information about the call.

Refer to the code below to define custom handling for distinct call events:

import {
  SignedCall,
  CallDirection,
  CallStatus,
  CallType,
  CallStatusDetails
} from '@clevertap/clevertap-signed-call-react-native';

//To start observing the changes in a call states.
SignedCall.addListener(
    SignedCall.SignedCallOnCallStatusChanged,
     (result: CallStatusDetails) => {
      console.log('SignedCallOnCallStatusChanged', result);

     if (result.direction === CallDirection.Incoming) {
         console.log('Call direction is Incoming!');
     } else if (result.direction === CallDirection.Outgoing) {
         console.log('Call direction is Outgoing!');
     }

  if (result.callType === CallType.M2P) {
    if (result.callStatus === CallStatus.DTMFInputReceived) {
      const dtmfInput = result.callOptions.getDtmfInput();
      if (dtmfInput) {
        console.log(`${dtmfInput.inputKey} is pressed!`);
      }
    } else if (result.callStatus === CallStatus.CallOver) {
      const dtmfInputList = result.callOptions.dtmfInputList;
      if (dtmfInputList) {
        console.log(`Size of DTMF inputs list: ${dtmfInputList.length}`);
      }
    }
    console.log(`${result.callStatus}, ${result.callOptions.campaignId}`);
  }

  switch (result.callStatus) {
    case CallStatus.CallIsPlaced:
      // Indicates that the call is successfully placed
      console.log('Call is successfully placed');
      break;

    case CallStatus.Declined:
      // Indicates that the call is declined from the receiver's end
      console.log('Call is declined from the receiver’s end');
      break;

    case CallStatus.Missed:
      // Indicates that the call is missed at the receiver's end
      console.log('Call is missed at the receiver’s end');
      break;

    case CallStatus.Answered:
      // Indicates that the call is picked up by the receiver
      console.log('Call is answered by the receiver');
      break;

    case CallStatus.CallInProgress:
      // Indicates that the connection to the receiver is established, and the audio transfer begins at this state
      console.log('Call is in progress');
      break;

    case CallStatus.CallOver:
      // Indicates that the call is over
      console.log('Call is over');
      break;

    case CallStatus.CalleeBusyOnAnotherCall:
      // Indicates that the receiver is already busy on another call
      console.log('Receiver is busy on another call');
      break;

    case CallStatus.DeclinedDueToLoggedOutCuid:
      // Indicates that the call is declined due to the receiver being logged out with the specific CUID
      console.log('Call is declined due to logged-out CUID');
      break;

    case CallStatus.DeclinedDueToNotificationsDisabled:
      // Indicates that the call is declined due to notifications being disabled at the receiver's end
      console.log('Call is declined due to notifications being disabled');
      break;

    case CallStatus.CallCancelledDueToTtlExpired:
      // Indicates that the campaign call is cancelled due to TTL being expired
      console.log('Call is cancelled due to TTL expired');
      break;

    case CallStatus.CallCancelledDueToCampaignNotificationCancelled:
      // Indicates that the M2P call is cancelled by clicking on cancel CTA from campaign's pre-processing notification
      console.log(
        'Call is cancelled by clicking on cancel CTA from campaign’s notification'
      );
      break;

    case CallStatus.DTMFInputReceived:
      // Indicates that a DTMF input is received from M2P keypad screen
      console.log('DTMF input is received from M2P keypad screen');
      break;

    default:
      // Handle any unexpected or unhandled statuses
      console.log('Unhandled call status:', result.callStatus);
      break;
  }
});

// To stop observing the changes in a call state.
SignedCall.removeListener(SignedCall.SignedCallOnCallStatusChanged);
import {
  SignedCall,
  CallDirection,
  CallStatus,
  CallType,
  CallStatusDetails
} from '@clevertap/clevertap-signed-call-react-native';

// To start observing the changes in call states.
SignedCall.addListener(SignedCall.SignedCallOnCallStatusChanged, (result) => {
  console.log('SignedCallOnCallStatusChanged', result);

  if (result.direction === CallDirection.Incoming) {
    console.log('Call direction is Incoming!');
  } else if (result.direction === CallDirection.Outgoing) {
    console.log('Call direction is Outgoing!');
  }

  if (result.callType === CallType.M2P) {
    if (result.callStatus === CallStatus.DTMFInputReceived) {
      const dtmfInput = result.callOptions.getDtmfInput();
      if (dtmfInput) {
        console.log(`${dtmfInput.inputKey} is pressed!`);
      }
    } else if (result.callStatus === CallStatus.CallOver) {
      const dtmfInputList = result.callOptions.dtmfInputList;
      if (dtmfInputList) {
        console.log(`Size of DTMF inputs list: ${dtmfInputList.length}`);
      }
    }
    console.log(`${result.callStatus}, ${result.callOptions.campaignId}`);
  }

  switch (result.callStatus) {
    case CallStatus.CallIsPlaced:
      // Indicates that the call is successfully placed
      console.log('Call is successfully placed');
      break;

    case CallStatus.Declined:
      // Indicates that the call is declined from the receiver's end
      console.log('Call is declined from the receiver’s end');
      break;

    case CallStatus.Missed:
      // Indicates that the call is missed at the receiver's end
      console.log('Call is missed at the receiver’s end');
      break;

    case CallStatus.Answered:
      // Indicates that the call is picked up by the receiver
      console.log('Call is answered by the receiver');
      break;

    case CallStatus.CallInProgress:
      // Indicates that the connection to the receiver is established, and the audio transfer begins at this state
      console.log('Call is in progress');
      break;

    case CallStatus.CallOver:
      // Indicates that the call is over
      console.log('Call is over');
      break;

    case CallStatus.CalleeBusyOnAnotherCall:
      // Indicates that the receiver is already busy on another call
      console.log('Receiver is busy on another call');
      break;

    case CallStatus.DeclinedDueToLoggedOutCuid:
      // Indicates that the call is declined due to the receiver being logged out with the specific CUID
      console.log('Call is declined due to logged-out CUID');
      break;

    case CallStatus.DeclinedDueToNotificationsDisabled:
      // Indicates that the call is declined due to notifications being disabled at the receiver's end
      console.log('Call is declined due to notifications being disabled');
      break;

    case CallStatus.CallCancelledDueToTtlExpired:
      // Indicates that the campaign call is cancelled due to TTL being expired
      console.log('Call is cancelled due to TTL expired');
      break;

    case CallStatus.CallCancelledDueToCampaignNotificationCancelled:
      // Indicates that the M2P call is cancelled by clicking on cancel CTA from campaign's pre-processing notification
      console.log(
        'Call is cancelled by clicking on cancel CTA from campaign’s notification'
      );
      break;

    case CallStatus.DTMFInputReceived:
      // Indicates that a DTMF input is received from M2P keypad screen
      console.log('DTMF input is received from M2P keypad screen');
      break;

    default:
      // Handle any unexpected or unhandled statuses
      console.log('Unhandled call status:', result.callStatus);
      break;
  }
});

// To stop observing the changes in a call state.
SignedCall.removeListener(SignedCall.SignedCallOnCallStatusChanged);

Handle Call Events in Killed State

πŸ“˜

Default Listener Behavior

The SignedCall.SignedCallOnCallStatusChanged listener receives updates only when the app is open or running in the background, not when it is in killed state.

To enable the SignedCall.SignedCallOnCallStatusChanged listener in the killed state, follow these two steps:

  1. Add the following code to the onCreate() method of your Application class:
SignedCallOnCallStatusListener.register(this);
SignedCallOnCallStatusListener.register(this)
  1. Register the SignedCall.SignedCallOnCallStatusChanged listener in the index.js file. It is the entry point of the React Native application. For a sample implementation, refer to index.js file of the Signed Call React Native Example Project.

The setup is now complete to receive call events in the killed state.

Handle Missed Call

If the receiver misses a call, the Signed Call React Native SDK shows a missed call notification to the receiver. The Signed Call React Native SDK uses action buttons on the missed call notification to display a Call to Action (CTA).

To configure the CTA on the missed call notification, add the following code:

  1. Create a Map object for missedCallActions parameter with a maximum of three entries.
let missedCallActionsMap = {
      '<Unique Identifier 1>': '<label on action-button 1>',
      '<Unique Identifier 2>': '<label on action-button 2>',
      '<Unique Identifier 3>': '<label on action-button 3>',
};
 
let initProperties = {
  ....
  missedCallActions: missedCallActionsMap,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
let missedCallActionsMap = {
      '<Unique Identifier 1>': '<label on action-button 1>',
      '<Unique Identifier 2>': '<label on action-button 2>',
      '<Unique Identifier 3>': '<label on action-button 3>',
};
 
let initProperties = {
  ....
  missedCallActions: missedCallActionsMap,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });
  1. Insert the following code to subscribe to the MissedCallActionClickResult event stream, allowing you to listen for CTA click events on missed call notifications:
import {
  SignedCall,
  MissedCallActionClickResult,
} from '@clevertap/clevertap-signed-call-react-native';

SignedCall.addListener(
      SignedCall.SignedCallOnMissedCallActionClicked,
      (event: MissedCallActionClickResult) => {
        console.log('SignedCallOnMissedCallActionClicked', event);
        Alert.alert(
          'Missed Call Notification!',
          event.action.actionLabel + ' is clicked'
        );
      }
    );
import {
  SignedCall,
  MissedCallActionClickResult,
} from '@clevertap/clevertap-signed-call-react-native';

//To start observing the CTA click on a missed call notification.
SignedCall.addListener(
      SignedCall.SignedCallOnMissedCallActionClicked,
      event => {
        console.log('SignedCallOnMissedCallActionClicked', event);
      }
    );

//To stop observing the CTA click on a missed call notification.
SignedCall.removeListener(SignedCall.SignedCallOnMissedCallActionClicked);

πŸ“˜

Killed state support for SignedCall.SignedCallOnMissedCallActionClicked

To enable the SignedCall.SignedCallOnMissedCallActionClicked listener in killed state, register the SignedCall.SignedCallOnMissedCallActionClicked listener in the index.js file, the entry point of the React Native application. For a sample implementation, refer to index.js file of the Signed Call React Native Example Project.

Debugging

Signed Call React Native SDK logs are, by default, set to the LogLevel.info level. We recommend you set the log level to LogLevel.verbose mode to log warnings or other important messages during development. If you want to disable the Signed Call React Native SDK logs for the production environment, you can set the debug level to LogLevel.off.

SignedCall.setDebugLevel(LogLevel.info); //default level, shows minimal SDK integration related logging

SignedCall.setDebugLevel(LogLevel.debug); //shows debug output

SignedCall.setDebugLevel(LogLevel.verbose); //shows verbose output

SignedCall.setDebugLevel(LogLevel.off);  //disables all debugging
SignedCall.setDebugLevel(LogLevel.info); //default level, shows minimal SDK integration related logging

SignedCall.setDebugLevel(LogLevel.debug); //shows debug output

SignedCall.setDebugLevel(LogLevel.verbose); //shows verbose output

SignedCall.setDebugLevel(LogLevel.off);  //disables all debugging

The log window displays the logs from the Signed Call SDKs. After setting the debug level, search for the following tags:

PlatformTAG
Android[CT]:[SignedCall]
React Native[CT]:[SignedCall]:[RN]

Sample Project: Implementing Signed Call React Native SDK

For example, for a project integrating Signed Call React Native SDK in your React Native application, refer to Signed Call React Native Example Project.

πŸ“˜

Note

Ensure you have added valid Signed Call and CleverTap Account credentials for the calling to work.

Error Handling

The Signed Call React Native SDK provides error reporting and handling.

The SignedCall.initialize(..) method is associated with promise objects that receive a SignedCallResponse object. This object contains any initialization that may occur.

The following is the list of the initialization errors:

Error CodeDescription
1000No internet connection.
2000The application context is missing.
2001The CleverTapApi instance is missing.
2002The initProperties is missing.
2003The Signed Call Android SDK is not initialized.
2004The accountId and apiKey parameters are missing.
2005The cuid is missing.
2006The cuid length is invalid.
2007Invalid cuid due to violation of valid cuid rules.
2008The length of the name parameter is invalid.
2009The appId is invalid.
2010The branding configuration is invalid.
2011The values in initProperties are invalid.
2012The user authentication is not successful.
2013The notification permission was not given during the SDK initialization.

FAQs

Is Signed Call accountId and apiKey the same as CleverTap accountId and token?

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.

Does the Signed Call React Native SDK support In-App calls over Bluetooth?

Yes. The Signed Call React Native SDK has built-in Bluetooth support. However, it requires a runtime BLUETOOTH_CONNECT permission for Android 12 and onwards.