Notification Support
Kindly notification support in handover
First provide the SDK with the FCM token using:
KindlySDK.saveNotificationToken(token = "firebase_token")When a push notification is received
Forward the notification to SDK using
KindlySDK.handleNotification(remoteMessage = remoteMessage)The SDK will double-check if notification type is a Kindly notification before handling it.
Check if a notification is from Kindly
To determine if a notification should be handled by the Kindly SDK or another notification provider, use the following helper method:
val isKindlyNotification = KindlySDK.isKindlyNotification(remoteMessage)This can be particularly useful when integrating with multiple push notification providers. Example usage:
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (KindlySDK.isKindlyNotification(remoteMessage)) {
// Handle with Kindly SDK
KindlySDK.handleNotification(remoteMessage)
} else {
// Handle with another notification provider (e.g., Braze, mParticle)
otherNotificationProvider.handleNotification(remoteMessage)
}
}Both calls work before start().
Process death and cold start
FCM delivers Kindly's data-only messages to onMessageReceived even when the app process is not running. In that process nothing has called KindlySDK.start(...) yet; the SDK decrypts the push with the key it persisted when the chat registered the device and posts the banner on its own. shouldHandleNotification is still asked when your interface is set in this process (after kill()); a fresh process has none. A device that never registered has no key and the push is dropped.
Tapping the notification
Tapping a Kindly banner opens the chat. If the SDK is not started, the tap launches your launcher activity and the chat opens as soon as start() runs (a tap older than 60 seconds is dropped). Set KindlySDK.openChatOnNotificationTap = false to only launch the app, and read the tap with KindlyNotificationIntent.read(intent) in onCreate / onNewIntent if you want to route it yourself.
When the SDK Displays the Notification
Kindly pushes are data-only FCM messages with encrypted content; the SDK decrypts each one and posts a system notification with the decrypted title/body â except when the chat conversation is on screen. The display rule is:
App state | Active screen | SDK presents the banner? |
|---|---|---|
Background | any | â Yes |
Foreground | Chat conversation on screen | â No (the user can already see the message) |
Foreground | Settings, language, image preview, host-app screens, etc. | â Yes |
Intercepting Notifications (shouldHandleNotification)
Every Kindly push that the SDK successfully decrypts while it is started is forwarded to the host app via the shouldHandleNotification(notification) method on KindlySDKInteraction â regardless of foreground/background state or which screen is on top. Before start() (process death) the SDK posts the banner without calling it. Use it to run side effects (analytics, logging, in-app indicators) or to take over the presentation entirely with your own UI.
Scenario | Result |
|---|---|
Interface not set | SDK presents the notification (subject to the display rule above) |
shouldHandleNotification returns true (default) | SDK presents the notification (subject to the display rule above) |
shouldHandleNotification returns false | SDK does not present anything â your app handles it |
The interface receives a ExternalNotification containing the decrypted fields plus the original RemoteMessage.data map for any extra fields your backend attached:
data class ExternalNotification(
val id: String, // decrypted chat_id
val title: String, // decrypted title
val body: String, // decrypted body
val data: Map<String, String>, // original RemoteMessage.data
)Implementation
KindlySDK.`interface` = object : KindlySDKInteraction {
override fun didPressButton(chatButton: ButtonChat, chatLog: List<MessageChat>) {
// Handle button press if needed
}
override fun shouldHandleNotification(notification: ExternalNotification): Boolean {
// Always log every Kindly notification, regardless of who presents it
Analytics.track("kindly_notification_received", notification.id)
// Example: take over presentation when the app is in a custom in-app inbox
if (isShowingCustomInbox) {
customInbox.add(notification)
return false // SDK does not present its banner
}
return true // let the SDK present the banner
}
}Notes
- The method has a default implementation that returns true, so you only need to override it if you want to observe or intercept notifications.
- The callback fires for every successfully decrypted Kindly push â it is not gated by the SDK's foreground/chat-screen display rule. Use it for analytics that need to run even when the SDK is on screen.
- The polarity matches shouldHandleLink: returning true means "the SDK should handle this", returning false means "I'll handle it myself".
- Returning false only suppresses the system notification â the underlying message has already been delivered to the chat session via the websocket / /latest endpoint, so it will appear in the chat history when the user opens it.