Go Back

Agora & Sendbird SDK Integration in iOS Application

Agora & Sendbird SDK Integration in iOS Application
Posted by
Technostacks
Nov 28 2023

With smartphones, chat capabilities have become common for mobile apps, and messaging apps are all the rage. The engagement that comes with chat features will unarguably push your users to spend more and more time on the app. Modern chat apps support not only text messages but also multimedia elements like images, videos, GIFs, and audio calls & video calling.

While implementing chat features, you can write everything by yourself or use some scaffolding from others to make the development faster.

Below is the list of available 3rd party SDKs (Software Development Kits) for integrating chat audio & video calling functionality into iOS applications.

Here are some popular and most used SDK options:

  • Sendbird
  • Firebase Real-time Database and Firebase Cloud Messaging
  • Twilio
  • Agora
  • Zendesk Chat SDK
  • PubNub

We have implemented all the above SDKs in our various areas of iOS applications.

We will discuss here the Agora & SendBird SDK implementation and the key features of both SDKs.

Agora SDK (Chat & Video Calling With Streaming Video Content)

Agora SDK (Software Development Kit) is a bundle of tools, libraries, and APIs provided by Agora, Inc. to developers with the sole aim of enabling them to infix their functions for real-time audio, video, and interactive broadcasting into their own apps. The foremost Agora SDK is used to aid in the integration of mechanisms through which applications can provide users with real-time communication, collaboration, and interaction.

Key Features Of The Agora SDK

Voice and Video Communication

The Agora SDK allows the developers to build the user interface of voice and video calling in the application. In other words, with the Agora SDK, as an example from our side, a user is able to make a one-to-one call or make a group call.

Interactive Broadcasting

The use of the Agora SDK can be by developers in making interactive broadcasting applications where one or more hosts may broadcast themselves to a large audience but at the same time enable the audience to interact via chat, likes, and many others.

Real-Time Messaging

The SDK makes not only voice calls but also video calls and empowers real-time text messaging and chat functionalities for conversation amongst users in the time of voice or video calls and standalone message applications.

Screen Sharing

Developers can also enable screen sharing in their apps, whereby the user is able to share their screens with other users during a call.

Cross-Platform Support

Agora SDK is versatile since it is compatible with iOS and Android devices, web browsers, and desktop applications making developers enjoy uniform experiences on various devices.

High Quality and Low Latency

Agora has emphasized in high audio and video quality as well as good latency to make the communication experience all smooth and immersive.

Customization and Integration

The SDK offers customization options fitting the branding and user experience of the host application. It also provides, then the APIs to integrate the real-time communication features seamlessly into the UI of the app.

You can Integrate the Agora SDK in various applications, such as video conferencing apps, social networking platforms, e-learning platforms, and virtual events, among others.

Read More:- Localization in SwiftUI – String Catalogs with Xcode 15

Agora SDK Implementation Guide for iOS Applications

Prerequisites

Xcode (latest version)

  • A valid Agora account (sign up at [Agora Developer Portal](https://www.agora.io/en/)
  • An iOS device or simulator running iOS 9.0 or later.

SDK Installation

  • Using CocoaPods
  • Open your project’s `Podfile`.
  • Add the following line to your `Podfile`:
  • pod ‘AgoraRtcKit’
    – Run the command `pod install` in your project directory.
    – Open the `.xcworkspace` file generated by CocoaPods.

  • Manual Integration
  • – Download the Agora SDK from the [Agora Developer Portal](https://www.agora.io/en/).
    – Drag and drop the `AgoraRtcKit.framework` file into your Xcode project.
    – In your project’s target settings, under “General,” add the `AgoraRtcKit.framework` to the “Frameworks, Libraries, and Embedded Content” section.

  • Initializing the Agora SDK
  • – Replace `”APP_ID”` with your Agora App ID.

    import AgoraRtcKit
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions
                      launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        AgoraRtcEngineKit.sharedEngine(withAppId: "YOUR_APP_ID", delegate: nil)
        return true
    
  • Implement the user interface
  • – To implement the user interface, create two views for the display of local and remote videos.

    // The video feed for the local user is displayed here
    var localView: UIView!
    // The video feed for the remote user is displayed here
    var remoteView: UIView!
    remoteView.frame = CGRect()
    localView.frame = CGRect()
    func initViews() {
        // Initializes the remote video view. This view displays video when a remote host joins the channel.
        remoteView = UIView()
        self.view.addSubview(remoteView)
        // Initializes the local video window. This view displays video when the local user is a host.
        localView = UIView()
        self.view.addSubview(localView)
    }
    
  • Permissions on the device
  • – First, we need to get permission for the camera and microphone, for that add these two permission keys to the info.Plist file.

    NSCameraUsageDescription
    $(PRODUCT_NAME) uses the camera for video call
    Privacy - Microphone Usage Description
    $(PRODUCT_NAME) uses the microphone for video call
    

    – Here is the Apple native AVCaptureDevice class to ask for permission before starting the camera.

    func requestCameraAccess() -> Bool {
            var hasCameraPermission = false
            let semaphore = DispatchSemaphore(value: 0)
            switch AVCaptureDevice.authorizationStatus(for: .video) {
                
            case .notDetermined:
                AVCaptureDevice.requestAccess(for: .video,
                                              completionHandler: { granted in
                    hasCameraPermission = granted
                    semaphore.signal()
                })
                semaphore.wait()
                return hasCameraPermission
            case .restricted:
                AVCaptureDevice.requestAccess(for: .video,
                                              completionHandler: { granted in
                    hasCameraPermission = granted
                    semaphore.signal()
                })
                semaphore.wait()
                return hasCameraPermission
            case .denied:
                return false
            case .authorized:
                return true
    
            @unknown default:
                AVCaptureDevice.requestAccess(for: .video,
                                               completionHandler: { granted in
                    hasCameraPermission = granted
                    semaphore.signal()
                })
                semaphore.wait()
                return hasCameraPermission
            }
            
        }
    

    – Also, need to request audio permission using the same AVCaptureDevice class.

    func requestAudioAccess() -> Bool {
            var hasAudioPermission = false
            let semaphore = DispatchSemaphore(value: 0)
            AVCaptureDevice.requestAccess(for: .audio, completionHandler: { granted in
                hasAudioPermission = granted
                semaphore.signal()
            })
            semaphore.wait()
            return hasAudioPermission
        }
    
  • Create a channel and generate a video token
  • In our case, we have generated a unique channel using the random alphanumeric string function and get a video token and streaming token from the backend API.

    func init() {
    	if checkForPermissions() {
    			if userType == .userHost {
                    self.getStreamingTokenAndJoinCall()
                } else {
                // if a user is not hosting this video call, we get this channel name, a token from firebase notification passed by the host user
                     self.userId = UInt("logged user-id")
                    self.agoraManager.channelName = channelName ?? ""
                    self.agoraManager.videotoken  = token ?? ""
                    self.agoraManager.streamingToken = token ?? ""
                    self.joinChannel()
                }
        }
    }
    
    var userId:UInt = 0
    var playerId:Int = 1001
    var channelName = ""
    var videocallChanneltoken = ""
    var streamingChanneltoken = ""
    var videoURL:String?
    
    func randomAlphaNumericString(length: Int) -> String {
            let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
            let allowedCharsCount = UInt32(allowedChars.count)
            var randomString = ""
            
            for _ in 0 ..< length {
                let randomNum = Int(arc4random_uniform(allowedCharsCount))
                let randomIndex = allowedChars.index(allowedChars.startIndex, offsetBy: randomNum)
                let newCharacter = allowedChars[randomIndex]
                randomString += String(newCharacter)
            }
        return randomString
    }
    
    func getStreamingTokenAndJoinCall() {
        let channelName = randomAlphaNumericString(length: 5)
        DispatchQueue.main.sync {
            self.userId = UInt("logged user id")
            self.agoraManager.channelName = channelName ?? ""
            self.agoraManager.videotoken  = videocallChanneltoken ?? ""
            self.agoraManager.streamingToken = streamingChanneltoken ?? ""
            self.playerId = playerID ?? 1001
            self.joinChannel()
        }
    }
    
  • Joining a Channel
  • To join a channel for real-time communication, We can use the channel ID.

    agoraKit.joinChannel(byToken: nil, channelId: "yourChannelId", info: nil, uid: 0, joinSuccess: nil)
    
  • Publishing and Subscribing to Streams
  • To publish your own audio and video stream, you'll need to configure the local media settings and then start publishing.

    agoraKit.enableVideo() // Enable video
    agoraKit.enableAudio() // Enable audio
    
    // Setup local video view
    let localVideoView = UIView() agoraKit.setupLocalVideo(localVideoView)
    
    // Start publishing
    agoraKit.startPreview()
    agoraKit.startPublishing()
    
  • Join a Stream
  • As a host user, you can also publish media streams in video calls using the Agora mediakit player.

    // push video url in agora mediakit player
     self.agoraManager.mediaPlayerKit.open(videoURL ?? "00", startPos: 0)
     self.agoraManager.publishStream(channelName: agoraManager.channelName,
                                                        UId: playerId)
    
  • Displays a remote video stream
  • - Callback called when a new host joins the channel.

    extension ViewController: AgoraRtcEngineDelegate {
        func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
            let videoCanvas = AgoraRtcVideoCanvas()
            videoCanvas.uid = uid
            videoCanvas.renderMode = .hidden
            videoCanvas.view = remoteView
            agoraEngine.setupRemoteVideo(videoCanvas)
        }
    }
    
  • Subscribing to Streams
  • - To subscribe to other users' audio and video streams, you'll need to set up remote video views and then subscribe to the streams.

    // Your remote video view
    let remoteVideoView = UIView()
     agoraKit.setupRemoteVideo(remoteVideoView,
                              forUid: remoteUid)
    agoraKit.subscribeRemoteVideoStream(remoteUid,
                                         type: .video,
                                         streamType: .high,
                                        subscribeSuccess: nil)
    
  • Handling User Interface
  • - You should manage user interface elements that allow users to start/stop publishing and subscribing, as well as UI elements for displaying video views.

    - Leave Channel
    - When the user wants to end the communication session, make sure to leave the channel and release resources.

    agoraKit.leaveChannel(nil)
    agoraKit.stopPreview()
    agoraKit.setupLocalVideo(nil)
    agoraKit.setupRemoteVideo(nil, forUid: remoteUid)
    
  • Handling User Interactions
  • - Implement UI controls for actions like muting audio, disabling video, switching cameras, etc. Use Agora SDK methods to manage these interactions.

Sendbird SDK (In-App Chat API And SDK Platform)

Sendbird SDK makes it easy for retailers to connect buyers and sellers within the mobile app for increased conversions and engagement for better retention all with a superior support edge. Increase community growth at the same time reducing churn. Essential moderation tools to keep the conversation safe.

Read More:- Placing 3D Objects In Real-World With SwiftUI

Key Features Of The Sendbird SDK

1. Group channels

A feature to enable a chat among up to 100 users in a channel, public and private. In the group channel, it would take place through an invitation for a 1-on-1 or 1-to-N private chat for users while a public chat without permission would involve various users.

2. Push notifications

Ability to send a push notification for the user's devices in case of a new message.

3. Typing indicators

Indication of whether the other users in the channel are typing a message.

4. Read receipts

Allowing the user to be aware that their messages have been read by the other users in the channel.

5. Smart throttling

A feature to customize the number of messages displayed in a large group chat by adjusting the message loading speed.

6. Message Search

First, a feature that is to be added is a search specific to messages of the channel. Developers and users will be able to find messages by title in the desired channel.

7. Message metadata

Feature that allows developers to add extra data to the messages being sent.

8. Image auto-moderation

A feature that would allow automatic filtering of explicit image inventory messages or inappropriate image URLs.

9. TLS-based message encryption

A feature that enables the Sendbird server and client apps to have messages that are encrypted as required by the protection against eavesdropping, tampering, and message forgery demands of the Transport Layer Security (TLS).

10. Advanced analytics

A feature that allows user behavior analysis through nine different metrics occurring on channels, messages, and users.

These features enable instant communication, collaborative discussions happen, the ability to track messages, monitor content in forums, share multilingual experiences, there is seamless integration and a piece of cake. Do note that in the latest SDK versions, there might be additional features too.

Read More:- Create a 3D Floor Plan of an Interior Room Using RoomPlan

For implementing chat, there are 2 options available:

  • SendBird Chat SDK
  • On the other hand, the Chat SDK is more low-level and flexible and you have more control over how you want to implement and customize the chat experience inside your app.

  • SendBird UIKit
  • The SendBird UIKit SDK is a high-level library that essentially comes built on top of the Chat SDK. It provides pre-built UI components and ready-to-use user interface elements which through easy integration get to be added to your app.

Sendbird SDK Implementation Guide for iOS Applications

Beforehand, one has to create a SendBird application either through the SendBird Dashboard before integrating the SendBird Chat SDK. This application consists of all the fundamental elements of chat service including the user's profiles, exchanging messages, and communication channels. To get started with Chat SDK, you will need a unique Application ID of your SendBird application acquired from the dashboard.

The minimum requirements for Chat SDK for iOS are the following.

  • macOS
  • Xcode 14.1 and later
  • At least one device running iOS 11.0 and later
  • Swift 5.0 and later or Objective-C

Install SendBird chat SDK with either Swift Packages Or CocoaPods Or Carthage. If you don’t want to write all code on your own you can use the available open source code of SendBird UIKit and do modifications as per requirements.

You see the Sources folder in the source code of UIKit. To your existing project, you could add that folder and accordingly update the color themes and styles. You should add a NotificationService folder under Sample to add the things related to notifications.

Every time the connection state of your iOS app changes, the Chat SDK has to be awoken to respond in properly. In waking up the Chat SDK, you will want to start it up. Starting the Chat SDK calls for your Sendbird application's special APP_ID which is available on the Sendbird Dashboard.

This ID helps the SDK work smoothly with your app. In AppDelegate file, you need to import chat SDK like below:

import SendbirdChatSDK

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        let APP_ID = "APP_ID" //Specify your SendBird application ID
        SendbirdUI.initialize(applicationId: APP_ID) { // This is the origin.
            // Initialization of SendbirdUIKit has started.
            // Show a loading indicator.
        } migrationHandler: {
            // DB migration has started.
        } completionHandler: { error in
            // If DB migration is successful, proceed to the next step.
            // If DB migration fails, an error exists.
            // Hide the loading indicator.
        }
    }

Then set the current user. User information can be found on the dashboard.

//Case 1: user_id only
 SBUGlobals.currentUser = SBUUser(userId: "USER_ID")
        
 //Case 2: Specify all fields
 SBUGlobals.currentUser = SBUUser(userId: "USER_ID", nickname: "(Optional)NICK_NAME", profileURL: "(Optional)PROFILE_URL")

In our project, we create the user from the backend when user signup from the website and get the user_id or any other information related to the sendbird on Login and save a relevant data in UserDefault.

With the object instantiated with "SBUGroupChannelListViewController", you can present or push the object whatever you want to get the channel list. When you send some of these messages to any user, it will create a channel with 2 members if there is one-to-one communication or with more than 2 users if there is a group. The "distinct" property works as a toggle that will decide, each and every time that the same person would like to commence a conversation with the same people, whether to re-open an already existing chat channel or create one afresh. For one-to-one discussions, you should set the "distinct" property to true.

This way, you keep using the same channel for ongoing conversations, which is usually what you want. This is the code for presenting ViewController like this. You can also push the ViewController if you are already in the Navigation Controller.

 let mainVC = SBUGroupChannelListViewController()
 let naviVC = UINavigationController(rootViewController: self.mainVC)
 naviVC.modalPresentationStyle = .fullScreen
 naviVC.modalTransitionStyle = .crossDissolve
 self.present(naviVC, animated: true)

If you want to know more about Channel you can get it from their website.

https://sendbird.com/docs/chat/sdk/v4/ios/channel/overview-channel

To share the images, videos, or any other file you first have to add Privacy permission in Info. plist file.

Almost every user interface content can be customized including view layouts, list styles, and themes. This could be done by modifying the code that is placed inside the "Source" folder. This way it lets you control the visual look as well as the behavior of your app's interface altogether. The provided code is implemented according to MVVM architecture. You have the flexibility to change the titles and labels displayed on the screen as well. Customize the text that appears on buttons, headers, and labels to match your app's desired language, tone, or branding.

We added search particular channel in a search bar below the navigation bar. We changed the color theme and some headers and label text. You can see we have changed the left button of the navigation bar like this:

self.mainVC.headerComponent?.leftBarButton = self.createHighlightedBackButton()
//function for custom back button
func createHighlightedBackButton() -> UIBarButtonItem {
        let backButton = UIButton(type: .custom)
        backButton.frame = .init(x: 0, y: 0, width: 40, height: 40)
        backButton.setImage(UIImage(named: "fi_menu"), for: .normal)
        backButton.tintColor = UIColor.appSecondaryColor
        backButton.addTarget(self, action: #selector(onClickBack), for: .touchUpInside)
        let backBarButton = UIBarButtonItem(customView: backButton)
        return backBarButton
 }

If you wish to receive notifications even when your phone is in sleep mode or your app is running in the background, you can achieve this by taking the following steps:

Step 1: Obtain the Necessary Files

Before diving into the technical steps, make sure you have the required files ready:

  • APNs Authentication Key (.p8): If you're using Apple's Push Notification Service (APNs), generate an authentication key (.p8) from the Apple Developer account. This key will be used to securely send push notifications to iOS devices.
  • SendBird Dashboard Access: Log in to your SendBird Dashboard account, where you'll set up push notifications for your SendBird application.

Step 2: Configure Push Notifications in SendBird Dashboard

  • Log in to your SendBird Dashboard account.
  • Navigate to your SendBird application.
  • Under the "Settings" section, locate the "Push Notifications" tab.
  • Upload the APNs authentication key (.p8) file that you generated earlier.

Step 3: Integrate Push Notifications in Your App

  • In your iOS app project, add the APNs authentication key (.p8) file.
  • Implement the necessary code to handle push notifications:
  • func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
           
            //Register a device token to SendBird server
            SendbirdUI.registerPush(deviceToken: deviceToken) { success in
                
     }
    
     
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
            let userInfo = response.notification.request.content.userInfo
            
            guard let payload: NSDictionary = userInfo["sendbird"] as? NSDictionary else { return }
            
            let havePresentedVC = UIApplication.shared.currentWindow?.rootViewController?.presentedViewController != nil
            let isSignedIn = UserDefaultHelper.isLoggedIn ?? false
            let needToPedning = !(isSignedIn || havePresentedVC)
            
            if needToPedning {
                self.pendingNotificationPayload = payload
            } else {
                guard let channel: NSDictionary = payload["channel"] as? NSDictionary,
                      let channelURL: String = channel["channel_url"] as? String else { return }
                
                let sceneDelegate = UIApplication.shared.connectedScenes
                    .first!.delegate as! SceneDelegate
                
                if havePresentedVC {
                    SendbirdUI.moveToChannel(channelURL: channelURL, basedOnChannelList: true)
                    sceneDelegate.drawerController.setDrawerState(.closed, animated: true)
                } else {
                    sceneDelegate.hightLightedRow = 2
                    sceneDelegate.channelUrl = channelURL
                    sceneDelegate.setNV(navId: .MessagesNV)
                    sceneDelegate.drawerController.setDrawerState(.closed, animated: true)
                }
            }
            completionHandler()
    }
    
    
    

If you want to remove push notification then you need to write below code. This code we have added in the logout function.

SendbirdUI.unregisterPushToken { success in
        SendbirdUI.disconnect { [weak self] in
             print("SendbirdUIKit.disconnect")
         }
}

If you want to add an audio/video call service, then it is also available in the sendbird call package.

There are many other features and functions that you will be able to handle when implementing SendBird. The above is just but an example of a short and fast implementation process for you to quickly know how to integrate SendBird into your application.

Conclusion

Here we have discussed how you can implement SendBird and Agora SDK in your iOS applications. We have also discussed the features and implementation guide of both the SDKs.

Technostacks is a leading mobile app development company, successfully accomplished projects in multiple sectors while considering the specific needs of their customers. With an experience of 10+ years, the team of professionals creates each project with a vision oriented towards the offering of solutions. We provide the services of developing chat, voice, and video calling apps for all industries that enable businesses to enhance their app’s user experience.

If you want to integrate video and chat functionalities or have a requirement for something related then you can contact us. Our dedicated developers have vast experience in creating mobile applications with ease and are able to meet your requirements.

X