let streamWrapper = StreamWrapper(
apiKey: "YOUR_API_KEY",
userCredentials: user,
tokenProvider: { result in
let token = \\ Fetch the token from your backend
result(.success(token))
}
)
Chat Integration
Introduction
It’s common for calling apps to have chat, as well as the opposite - chat apps to have a calling functionality. Stream’s Chat and Video SDKs are perfectly compatible between each other, and can easily be integrated into an app.
You can find an example chat integration with our video product, in our samples repo.
Adding chat into video
In this guide you will take a video-based application and add chat functionality with the Stream Chat SDK on top of it. Here is an example of what the end result will look like:
The starting point for this guide is a functioning video calling application. If you don’t have one and want to follow along, feel free to do our step-by-step tutorial first.
Connecting the Video and Chat Client
You should have a setup for both the video and chat client. They both require the same API key, as well as the same user token.
The sample repo contains a simple StreamWrapper
, that can help you initialize and connect both clients.
Here’s an example on how to initialize the StreamWrapper
:
Note that you can also setup the clients in a different way, without using this wrapper. More information on how to setup the Stream Chat SwiftUI SDK can be found here.
Adding Chat to the Call Controls
The simplest way to add chat to an existing video calling app is to extend the call controls with an additional chat icon. To do this, implement the makeCallControlsView
in your custom implementation of the ViewFactory
from the Stream Video SDK (in our case it’s called VideoWithChatViewFactory
, see here):
class VideoWithChatViewFactory: ViewFactory {
/* ... Previous code skipped. */
func makeCallControlsView(viewModel: CallViewModel) -> some View {
ChatCallControls(viewModel: viewModel)
}
}
Create a new SwiftUI view called ChatCallControls
and add the code for the ToggleChatButton
to the file (for example at the bottom):
struct ToggleChatButton: View {
@ObservedObject var chatHelper: ChatHelper
var body: some View {
Button {
// 1. Toggle chat window
withAnimation {
chatHelper.chatShown.toggle()
}
}
label: {
// 2. Show button
CallIconView(
icon: Image(systemName: "message"),
size: 50,
iconStyle: chatHelper.chatShown ? .primary : .transparent
)
// 3. Overlay unread indicator
.overlay(
chatHelper.unreadCount > 0 ?
TopRightView(content: {
UnreadIndicatorView(unreadCount: chatHelper.unreadCount)
})
: nil
)
}
}
}
The code does three interesting things (see the numbered comments):
- On tapping the button it toggles the chat window
- Showing a button that indicates that there is a chat to open
- It overlays an unread indicator when there’s new chat messages
Here’s the (simplified, see full version) implementation of the ChatCallControls
itself, that handles the display of the chat inside it.
struct ChatCallControls: View {
@ObservedObject var viewModel: CallViewModel
@StateObject private var chatHelper = ChatHelper()
public var body: some View {
// 1. Arrange code in VStack
VStack {
HStack {
ToggleChatButton(chatHelper: chatHelper)
// Unrelated code skipped. Check repository for complete code:
// https://github.com/GetStream/stream-video-ios-examples/blob/main/VideoWithChat/VideoWithChat/Sources/ChatCallControls.swift
}
// 2. If chat is activated, show the ChatChannelView
if chatHelper.chatShown {
if let channelController = chatHelper.channelController {
ChatChannelView(
viewFactory: ChatViewFactory.shared,
channelController: channelController
)
.frame(height: UIScreen.main.bounds.height / 3 + 50)
.onAppear {
chatHelper.markAsRead()
}
} else {
Text("Chat not available")
}
}
}
.frame(maxWidth: .infinity)
.frame(height: chatHelper.chatShown ? (UIScreen.main.bounds.height / 3 + 50) + 100 : 100)
/* more modifiers */
// 3. Listen to changes in call participants and update the UI accordingly
.onReceive(viewModel.$callParticipants, perform: { output in
if viewModel.callParticipants.count > 1 {
chatHelper.update(memberIds: Set(viewModel.callParticipants.map(\.key)))
}
})
}
}
The lines that are marked do the following:
- The entire code is wrapped in a
VStack
to show content vertically, with chat being slid in from the bottom, once shown. The buttons on the other hand are wrapped in aHStack
. - If
chatHelper.chatShown
is true and achannelController
can be retrieved, theChatChannelView
from the Stream Chat SDK is used to display chat. - Subscribing to changes in the
callParticipants
allows to make sure the UI is always up-to-date.
Note that both the Video and Chat SDK should be setup with the same API key and token, before displaying this view.
Not sure how to do this? Start here for video and here for chat.
That’s everything that’s needed to add a button in the call controls, that will show a chat during the call.
Conclusion
In this article, we have seen how the two SDKs for chat and video can work together.
For more examples on how to create enganging video experiences, please check our video cookbook and UI components.
You can find more details about our chat SDK in the chat docs.