SDK Delegate (ChatCenterUISDKDelegate)
ChatCenterUISDKDelegate is a protocol for receiving events from the SDK. All methods have default implementations (empty; didOpen returns false), so implement only the ones you need.
In the current SDK version all delegate methods are in practice called on the main thread, but this is not part of the contract — the protocol is not marked @MainActor. For reliability, wrap UI updates in DispatchQueue.main.async:
func chatCenterUI(chatCenter: ChatCenterUISDK, didChangeUnreadMessages count: Int) {
DispatchQueue.main.async {
self.updateBadge(count: count)
}
}
Setting the delegate
Assign the delegate after initializing the SDK:
chatCenterSDK.delegate = self
Declare conformance to the protocol in the appropriate class:
extension MyViewController: @preconcurrency ChatCenterUISDKDelegate {
// implement the methods you need
}
The @preconcurrency attribute is only needed when building with the strict concurrency checker (SWIFT_STRICT_CONCURRENCY=complete or Swift 6). Otherwise it can be omitted.
Delegate methods
didChangeUnreadMessages
func chatCenterUI(chatCenter: ChatCenterUISDK, didChangeUnreadMessages count: Int)
Called when the unread message count changes.
When it is called:
- When the unread counter changes — after the chat history has been loaded (the SDK loads history automatically after
authorize(user:); opening the chat screen is not required for this). - Periodically via the
getUnreadMessagesCountREST request, ifChatConfig.unreadMessageCountDelay > 0is set. The SDK sends the next requestunreadMessageCountDelayseconds after the previous one completes — the actual interval may exceed the configured value by the request duration. - Once with a value of
0when a new user authorizes (differentidentifieror token). Re-authorizing the same user with the same token does not trigger this call.
After deauthorizeUser the delegate stops receiving counter updates until the next authorization.
Parameters:
count: Number of unread messages.0means there are no unread messages.
While the chat screen is not open, the delegate does not receive instant updates for each incoming message — the counter is delivered via REST polling at the unreadMessageCountDelay interval. If unreadMessageCountDelay is not set or equals 0, polling does not run, and the delegate will not be called until the chat is opened again.
To update the badge when the app returns to the foreground or when a push notification arrives, additionally call getUnreadMessagesCount(completion:) on ChatCenterUISDK — the completion is delivered on the main thread:
// AppDelegate / SceneDelegate
func applicationWillEnterForeground(_ application: UIApplication) {
guard let sdk = chatCenterSDK else { return }
do {
try sdk.getUnreadMessagesCount { [weak self] result in
if case let .success(count) = result {
self?.updateChatBadge(count)
}
}
} catch {
// User is not authorized yet — refresh the counter after authorize.
}
}
Example — updating the badge on the chat button:
func chatCenterUI(chatCenter: ChatCenterUISDK, didChangeUnreadMessages count: Int) {
DispatchQueue.main.async {
self.chatButton.badge = count > 0 ? "\(count)" : nil
}
}
didReceiveNetwork
func chatCenterUI(chatCenter: ChatCenterUISDK, didReceiveNetwork error: Error)
Called on a REST request or file upload error.
In the current version, this method reports only REST-layer errors (including file uploads). WebSocket connection drops and errors are not delivered through this callback — to track the real-time channel status, use separate signals (for example, the state from send(message:), which throws ChatCenterUISendMessageError.webSocketNotActive).
Example:
func chatCenterUI(chatCenter: ChatCenterUISDK, didReceiveNetwork error: Error) {
Analytics.log("chat_network_error", parameters: ["error": error.localizedDescription])
}
didOpen url
func chatCenterUI(chatCenter: ChatCenterUISDK, didOpen url: URL) -> Bool
Called before a URL from a chat message (a link in text) is opened.
Return value:
true— the link is handled by your application; the SDK does nothing.false— the SDK tries to open the URL viaUIApplication.shared.open(_:), but only ifUIApplication.shared.canOpenURL(url)returnedtrue. Otherwise the link is silently ignored.
If the method is not implemented, the SDK behaves as if false were returned — it tries to open the link via UIApplication.shared.open(_:) with a canOpenURL check.
LSApplicationQueriesSchemescanOpenURL returns false for any scheme not listed in LSApplicationQueriesSchemes in your application's Info.plist. If chat messages may contain tel:, mailto:, custom deep link schemes, or third-party app links, add them explicitly:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>tel</string>
<string>mailto</string>
<string>myapp</string>
</array>
Otherwise the user taps the link and sees no reaction, and the SDK does not emit an error.
Example — intercepting a deep link, external links via SFSafariViewController:
import SafariServices
func chatCenterUI(chatCenter: ChatCenterUISDK, didOpen url: URL) -> Bool {
// Handle the app's internal deep link
if url.scheme == "myapp" {
DeepLinkRouter.handle(url)
return true
}
// Open external links via Safari in the app
let safariVC = SFSafariViewController(url: url)
present(safariVC, animated: true)
return true
}
didOpen returns Bool synchronously: the decision "I will handle it" (true) or "let the SDK open it" (false) is delivered to the SDK immediately. Asynchronous URL checks inside the method are not possible — if the decision depends on a network request, return false (subject to the canOpenURL constraints above) and handle the URL separately.
didLog
func chatCenterUI(chatCenter: ChatCenterUISDK, didLog event: String)
Called for every SDK logging event. Used to forward SDK logs into your own system — Firebase Crashlytics, Sentry, OSLog.
logLevelThe method respects ChatLoggerConfig.logLevel — events are delivered to the delegate only if their level matches the configured logLevel. With the default value .off, the delegate does not receive any events. To receive all logs in the delegate, use ChatLoggerConfig(logLevel: .all). Any additional filtering inside the delegate handler is up to your code.
Example:
func chatCenterUI(chatCenter: ChatCenterUISDK, didLog event: String) {
os_log("%{public}@", log: .default, type: .debug, event)
}
Method summary
| Method | When it is called | Returns |
|---|---|---|
didChangeUnreadMessages | When the unread counter changes (after history is loaded) and via REST polling at the ChatConfig.unreadMessageCountDelay interval, if it is set | — |
didReceiveNetwork | On a REST request or file upload error (WebSocket errors are not delivered) | — |
didOpen url | Before opening a URL from a chat message | Bool (handled?) |
didLog | On an SDK logging event whose level matches ChatLoggerConfig.logLevel | — |
Related sections
- SDK initialization options — assigning the delegate via the
delegateproperty - Messages and unread counter — the
getUnreadMessagesCountmethod - SDK configuration — the
keepSocketActiveparameter fordidChangeUnreadMessagesto work in the background