How to Enable Offline Access and Automatic Sync for Chat List and Messages in Sendbird SDK?

[Problem/Question]

Hello,

I am implementing chat functionality in my application using the Sendbird SDK. I want to ensure that users can access their chat list and individual chat messages even when they are offline. Additionally, when the internet connection is restored, the data should sync automatically with the server.

Could you please let me know if the Sendbird SDK supports this functionality, and if so, what steps or configurations are required to enable it?

Thank you in advance for your assistance!

Hello Deepanshu,

Sendbird Chat SDK includes a Local Caching feature that allows it to cache and retrieve group channel and message data locally. This feature offers several benefits, including reduced refresh times and the ability for client applications to create a channel list or chat view that functions both online and offline. Additionally, it supports offline messaging.

For more information, please refer to the following Chat SDKs:
Android Chat SDK - Local caching | Chat Android SDK | Sendbird Docs
iOS Chat SDK - Local caching | Chat iOS SDK | Sendbird Docs
JavaScript Chat SDK - Local caching | Chat JavaScript SDK | Sendbird Docs

Additionally, it appears that you might be using Sendbird Chat UIKit which supports Local caching by default.

Hi @uday.bhaskar
I have used message collection but it is not loading from it and there is no documentation how to use it in custom view controller as I’m using the sendbird ui kit and just overriding some of its properties in the existing cells.

var messagesViewController: CustomGroupChannelViewController!
var channel: GroupChannel?
var collection: MessageCollection?

override func viewDidLoad() {
super.viewDidLoad()

    // Initialize and configure Sendbird's GroupChannelViewController
    guard let channel else { return }
    messagesViewController = CustomGroupChannelViewController(channel: channel)
    
    // Add messagesViewController's view to the container
    addChild(messagesViewController)
    messageContainerView.addSubview(messagesViewController.view)
    messagesViewController.view.frame = messageContainerView.bounds
    messagesViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    messagesViewController.didMove(toParent: self)

    createMessageCollection()

}

//Create message collection
func createMessageCollection() {
let params = MessageListParams()
params.reverse = false // Fetch messages in ascending order
params.isInclusive = false // Exclude the startingPoint message
params.messageTypeFilter = .all
params.includeMetaArray = true // Include meta arrays
params.includeReactions = true // Include reactions

    self.collection = SendbirdChat.createMessageCollection(channel: channel!, startingPoint: Int64(Date().timeIntervalSince1970), params: params)
    self.collection?.delegate = self // Set the delegate to handle updates
    
    initializeMessageCollection()
}

// Initialize messages from startingPoint.
func initializeMessageCollection() {
    guard let collection = self.collection else { return }
    
    collection.startCollection(initPolicy: .cacheAndReplaceByApi, cacheResultHandler: { messages, error in
        guard error == nil else {
            print("Error fetching messages from cache: \(String(describing: error))")
            return
        }
        
        self.updateMessages(messages)
    }, apiResultHandler: { messages, error in
        guard error == nil else {
            print("Error fetching messages from API: \(String(describing: error))")
            return
        }
        
        self.updateMessages(messages)
    })
}

func messageCollection(_ collection: MessageCollection, context: MessageContext, channel: GroupChannel, updatedMessages: [BaseMessage]) {
    self.updateMessages(updatedMessages)
}

func messageCollection(_ collection: MessageCollection, context: MessageContext, channel: GroupChannel, deletedMessages: [BaseMessage]) {
    self.deleteMessages(deletedMessages)
}

func messageCollection(_ collection: MessageCollection, context: MessageContext, channel: GroupChannel, addedMessages: [BaseMessage]) {
    self.addMessages(addedMessages)
}

func didDetectHugeGap(_ collection: MessageCollection) {
    // Huge gap detected, reinitialize the collection
    collection.dispose()
    self.createMessageCollection()
}

private func updateMessages(_ newMessages: [BaseMessage]?) {
    guard let newMessages else {return}
    // Merge the new messages with the existing ones
    self.messages = newMessages.sorted(by: { $0.createdAt < $1.createdAt })
    self.messagesViewController.listComponent?.tableView.reloadData()
}

private func addMessages(_ newMessages: [BaseMessage]?) {
    guard let newMessages else {return}
    self.messages.append(contentsOf: newMessages)
    self.messages.sort(by: { $0.createdAt < $1.createdAt })
    self.messagesViewController.listComponent?.tableView.reloadData()
}

private func deleteMessages(_ deletedMessages: [BaseMessage]?) {
    guard let deletedMessages else {return}
    let deletedMessageIds = deletedMessages.map { $0.messageId }
    self.messages.removeAll { deletedMessageIds.contains($0.messageId) }
    self.messagesViewController.listComponent?.tableView.reloadData()
}