Set Up Video Calling for React Native

Updated 

Brands can integrate video calling into their mobile apps through Sprinklr Messenger. This guide explains how to integrate and configure video calling in Sprinklr Messenger for React Native using the Amazon Chime SDK.

Prerequisites

To integrate AWS Chime, ensure the following prerequisites are met:

  • AWS account with the Chime SDK enabled.

  • If you want to enable video recording, you need an S3 bucket associated with your AWS account to store Chime-side recordings.

  • AWS account number to process video call recordings​.

  • Permission to access Care Console in the Sprinklr platform​.

Note: You can enable AWS Chime account to make and receive video calls by reaching out to Sprinklr support at tickets@sprinklr.com.

Installation

1. Install the AWS Chime SDK.

Add the following package dependency to your package.json file:

"@sprinklrjs/chime-video": "2.0.1"

2. Register the video call provider.

In your application entry point, register the video call provider with the Messenger SDK before calling the takeOff method:

MessengerClient.registerVideoCallProviderConfig({  provider: 'AMAZON_CHIME',});

Configuring Push Notifications

You can configure push notification handling on Android and iOS, so that incoming calls and call notifications work properly.

Android

For Android, follow these steps:​

Step 1: Create MessengerPushService

This service is responsible for handling incoming push notifications. The implementation differs based on the notification library being used.

If using react-native-firebase, extend ReactNativeFirebaseMessagingService in your MessengerPushService.

The following is an example code. A similar Service class can be created for any other push notifications library as well.

Example:

package com.messengerexample;import android.util.Log;import com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService;import com.google.firebase.messaging.RemoteMessage;import com.sprinklr.messenger.SPRMessengerController;import java.util.Map;public class MessengerPushService extends RNPushNotificationListenerService {    private static final String TAG = "MessengerPushService";    @Override    public void onMessageReceived(RemoteMessage remoteMessage) {        Map<String, String> remoteData = remoteMessage.getData();        Log.d(TAG, remoteData.toString());        if (SPRMessengerController.shared().pusher().canHandlePushEvent(remoteData)) {            SPRMessengerController.shared().pusher().handlePushEvent(this, remoteData, MainActivity.class);        } else {            super.onMessageReceived(remoteMessage);        }    }    @Override    public void onNewToken(String token) {        super.onNewToken(token);    }}

Step 2: Register the Service in AndroidManifest.xml

Add the following to your <application> block:

<service    android:name="<your.package.name>.MessengerPushService"    android:exported="false">    <intent-filter>        <action android:name="com.google.firebase.MESSAGING_EVENT" />    </intent-filter></service>

Step 3: Link sprinklr-messenger-notifications package

In the settings.gradle file, include the following project:

include ':sprinklr-messenger-notifications'project(':sprinklr-messenger-notifications').projectDir = new File(rootProject.projectDir, '../node_modules/@sprinklrjs/chat-native-client/android/notifications')

In the app/build.gradle file, add the following dependency under the dependencies block:

implementation project(':sprinklr-messenger-notifications')

Step 4: Update the MainApplication.java file

  • Import the following:

import com.sprinklr.messenger.SPRMessengerController;import com.sprinklr.messenger.config.bean.SPRPusher;import com.sprinklr.messenger.NotificationPreferences;
  • In the onCreate() method, initialize the SPRMessengerController and optionally configure notification icons:

SPRMessengerController.initialize(SPRPusher::new, this, mReactNativeHost); // optional: to customize notification icons (should be done after SPRMessengerController.initialize)NotificationPreferences notificationPreferences = new NotificationPreferences();notificationPreferences.setSmallIcon(R.drawable.notification_icon); // for notification iconnotificationPreferences.setCallIcon(R.drawable.call_icon); // for call iconSPRMessengerController.shared().pusher().setSPRNotificationPreferences(notificationPreferences);

Step 6: Update the MainActivity.java file

import android.content.Intent;import com.sprinklr.messenger.SPRMessengerController;public class MainActivity extends ReactActivity {  // other methods  @Override  public void onResume() {    SPRMessengerController.shared().removeCallNotification(this, this.getIntent());    super.onResume();  }  @Override  public void onNewIntent(Intent intent) {    super.onNewIntent(intent);    SPRMessengerController.shared().removeCallNotification(this, intent);  } }

iOS

For iOS, follow these steps:

Step 1: Add VOIP support

Add the following in your Info.plist file:

<key>UIBackgroundModes</key><array><string>remote-notification</string><string>voip</string></array>

​Step 2: Implement PKPushRegistryDelegate methods

Make the following changes in the AppDelegate.m file:

#import <PushKit/PushKit.h>#import <SPRMessenger/SPRVoipPushNotificationManager.h>@interface AppDelegate () <PKPushRegistryDelegate>@end@implementation AppDelegate  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  {       PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];    voipRegistry.delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;    voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];    // other initializations    return [super application:application didFinishLaunchingWithOptions:launchOptions];  }  #pragma mark - PKPushRegistryDelegate methods  - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)pushCredentials forType:(PKPushType)type {    [[SPRVoipPushNotificationManager shared] didUpdatePushCredentials:pushCredentials forType:(NSString *)type];  }  - (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type {    [[SPRVoipPushNotificationManager shared] didInvalidatePushTokenForType:(NSString *)type];  }  - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {    if ([[SPRVoipPushNotificationManager shared] canHandleVoipPushEvent: payload]) {      [[SPRVoipPushNotificationManager shared] handleVoipPushEvent:payload forType:type completion:completion];      return;    }  }@end

Make the following changes in the AppDelegate.swift file:

import PushKitimport SPRMessenger@UIApplicationMainclass AppDelegate: PKPushRegistryDelegate {    func application(        _ application: UIApplication,        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil    ) -> Bool {        let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)        voipRegistry.delegate = self        voipRegistry.desiredPushTypes = [PKPushType.voIP]        // other initializations        return true    }    // MARK: - PKPushRegistryDelegate    func pushRegistry(        _ registry: PKPushRegistry,        didUpdate pushCredentials: PKPushCredentials,        for type: PKPushType    ) {        SPRVoipPushNotificationManager.shared().didUpdatePushCredentials(pushCredentials, forType: type.rawValue)    }    func pushRegistry(        _ registry: PKPushRegistry,        didInvalidatePushTokenFor type: PKPushType    ) {        SPRVoipPushNotificationManager.shared().didInvalidatePushToken(forType: type.rawValue)    }    func pushRegistry(        _ registry: PKPushRegistry,        didReceiveIncomingPushWith payload: PKPushPayload,        for type: PKPushType,        completionHandler completion: @escaping () -> Void    ) {        if SPRVoipPushNotificationManager.shared().canHandleVoipPushEvent(payload) {            SPRVoipPushNotificationManager.shared().handleVoipPushEvent(payload, forType: type.rawValue, completion: completion)            return        }    }}

Implementing Custom Video Call Icons

The Sprinklr Messenger Chime Video SDK allows host apps to override the default icons shown on the video call footer toolbar (camera, microphone, flip camera, and end call). If no custom icon is provided, the SDK continues to use its default icons.

Note: This customization is available only if Picture‑in‑Picture (PIP) mode is enabled in your Messenger configuration.

Android

On Android, customization is done by registering an icons provider in Application.onCreate() before Messenger initialization:

import com.spr.messengerchimevideoclient.SPRAmazonChimeConfig;import com.spr.messengerchimevideoclient.VideoCallIcon;SPRAmazonChimeConfig.setIconsProvider(icon -> {    if (icon == VideoCallIcon.END_CALL) {        return R.drawable.my_hangup_icon;    }    if (icon == VideoCallIcon.CAMERA_OFF) {        return R.drawable.my_camera_off_icon;    }    return null; // SDK default for unmapped slots});

API Methods

In the registration, the following methods are used:

  • setIconsProvider(provider): Register a provider. Pass null to clear it and revert to the SDK defaults.

  • getCustomIcon(icon): Return a non‑zero @DrawableRes ID, or null/0 to use the SDK default for that slot.

Customizable Icons

Icon

iconName

When Used

Flip Camera

FLIP_CAMERA

Switch Front/Rear camera

Camera On

CAMERA_ON

Local video enabled

Camera Off

CAMERA_OFF

Local video disabled

Microphone On

MIC_ON

Microphone unmuted

Microphone Muted

MIC_MUTED

Microphone muted

End Call

END_CALL

Hang up

iOS

To customize icons, implement the SPRAmazonChimeIconsDelegate. This delegate offers three optional customization methods:

  • getCustomIconName: This method returns the updated iconName to be used. By default, the iconName will be looked in the default symbol icon set provided by UIKit.

  • iconForName: This method returns the UIImage * instance which will be directly used as the icon for the given iconName.

  • assetBundleName: This property should be set if the application has a custom asset bundle which contains the customizable icons.

Note: All the three methods are optional.

Icon Resolution Order

If multiple methods are implemented, this is how the icon will be resolved:

  1. Defalt Icon Name: The default iconName will be passed to the getCustomIconName method if implemented. If not implemented, the iconName will remain unchanged.

  2. Use updatedIconName from Step 1: The updated iconName from step 1 will be used to resolve the asset further. Let’s call it updatedIconName.

  3. Check assetBundleName: If the assetBundleName property is specified, the updatedIconName will be resolved from the bundle specified. If the asset is not found, the resolution will move to the next step.

  4. Call iconForName: If the iconForName method is implemented, the updatedIconName will be passed to this method to get the resolved UIImage * instance.

  5. Fallback to default asset: If the image could not be resolved from any of the above steps, or no delegate method was implemented, the default asset will be used.

Implementation

#import <SPRChimeVideo/SPRAmazonChimeConfig.h>@interface AppDelegate () <SPRAmazonChimeIconsDelegate>@end@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  // other initializations  [SPRAmazonChimeConfig shared].iconsDelegate = self;  self.assetBundleName = @"MyAssetsBundle"; // if a custom asset bundle is to be used  return YES;}#pragma mark - SPRAmazonChimeIconsDelegate Method(s)- (NSString *)getCustomIconName:(NSString *)name {  if ([name isEqual: @"phone.down.fill"]) {    return @"phone.down.circle.fill"; // custom name mapping for call disconnect icon  }  return name; // return the default icon name}- (UIImage *)iconForName:(NSString *)name withConfig:(UIImageSymbolConfiguration * _Nullable)config {    // return the UIImage * instance for the icon name}@end

import UIKitimport SPRChimeVideo@mainclass AppDelegate: UIResponder, UIApplicationDelegate, SPRAmazonChimeIconsDelegate {    func application(        _ application: UIApplication,        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?    ) -> Bool {        // other initializations        SPRAmazonChimeConfig.shared().iconsDelegate = self        self.assetBundleName = "MyAssetsBundle" // if a custom asset bundle is to be used        return true    }    // MARK: - SPRAmazonChimeIconsDelegate    func getCustomIconName(_ name: String) -> String {        if name == "phone.down.fill" {            return "phone.down.circle.fill" // custom name mapping for call disconnect icon        }        return name // default icon name    }    func iconForName(        _ name: String,        with config: UIImage.SymbolConfiguration?    ) -> UIImage? {        // return the UIImage instance for the icon name    }}

Customizable Icons

Icon

iconName

When Used

Flip Camera

camera.rotate.fill

Switch Front/Rear camera

Camera On

video.fill

Local video enabled

Camera Off

video.slash.fill

Local video disabled

Microphone On

mic.fill

Microphone unmuted

Microphone Muted

mic.slash.fill

Microphone muted

End Call

phone.down.fill

Hang up

Support Video Continuity Outside Live Chat Interface

This feature allows users to continue a video or audio call even after they navigate away from the Live Chat interface and return to the host brand application. Without continuity, the video call must be disconnected before leaving the Live Chat interface. With continuity enabled, the call seamlessly continues outside the Live Chat interface.

Platform‑specific continuity behavior is as follows:

  • Android: Continuity works at the device level, allowing calls to persist outside the parent app.

  • iOS: Continuity works at the app level, so calls remain active only within the parent application.

Note: ​To enable Video Call Continuity, contact Sprinklr Support at tickets@sprinklr.com.