[go: up one dir, main page]

Setup

We support the following providers:

We ship an individual artifact for each of these to make client-side integration with their service quick and simple. See their individual documentation pages linked above for details.

Basic Setup

To enable push notifications, you need to configure the NotificationConfig with the required PushDeviceGenerator for your chosen provider. The PushDeviceGenerator is essential for registering your device with the push notification service.

Required configuration:

  • pushNotificationsEnabled: Set to true to enable push notifications (enabled by default)
  • pushDeviceGenerators: List of generators for your chosen push notification provider
val notificationConfig = NotificationConfig(
    pushNotificationsEnabled = true, // Enable push notifications
    pushDeviceGenerators = listOf(
        // Add your desired push device generators here
        // You can include multiple generators based on your needs
        FirebasePushDeviceGenerator(),
    ),
)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()

Push notifications are disabled by default on the client side. You can enable it by setting the NotificationConfig::pushNotificationsEnabled property to true. Keep in mind that the SDK creates a NotificationChannel during its initialization if push notifications are enabled client-side.

Customizing Push Notifications

If you want, you can also customize how the push notifications work.

You can customize push notifications in the following ways:

  • Overriding resources: Lets you customize notification’s icon and text resources
  • NotificationHandlerFactory: Uses the styles we provide but customizes an intent the user triggers when clicking on a notification.
  • NotificationHandler: Lets you fully customize how notifications are shown and dismissed
  • NotificationConfig::shouldShowNotificationOnPush: Lets you decide whether to show a notification after receiving a push

Overriding resources

You can provide custom icon and text resources displayed in notifications by overriding them:

The SDK supports multiple languages. Make sure to override resources in all languages used in your app. Refer to Adding Localization guide for more details.

Using our NotificationHandlerFactory

Our NotificationHandlerFactory provides a way to create a default implementation of NotificationHandler based on the Android API Level and lets you customize an intent that a user triggers by clicking the notification. This function lets you provide a custom Intent that can point to any Activity in your app. You can also add custom data to the Intent if you need it.

val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    context = context,
    notificationConfig = notificationConfig,
    newMessageIntent = { message: Message, channel: Channel ->
        // Return the intent you want to be triggered when the notification is clicked
        val intent: Intent = [....]
        intent
    }
)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()

Customize Notification Style

The SDK lets you define the theming and behavior of the notification UI that users see after they receive a push notification. To do this, implement the NotificationHandler interface and show your own notification. If you want to dismiss notifications when a user visits a channel or logs off of the app, you will need to implement methods for dismissing notifications on the NotificationHandler class.

The NotificationHandler interface provides several methods to handle different types of events:

  • onChatEvent(event: NewMessageEvent): Handles WebSocket events for new messages when the user is connected. This method is only invoked when the user has an active WebSocket connection. You can use this to control whether to show notifications while the user is active in the app. Return true to handle the event yourself, false to let the SDK handle it internally.
  • onNotificationReminderDueEvent(event: NotificationReminderDueEvent): Handles WebSocket events for reminder notifications when the user is connected. This method is only invoked when the user has an active WebSocket connection. Return true to handle the event yourself, false to let the SDK handle it internally.
  • onPushMessage(message: PushMessage): Acts as a bypass to control whether push notifications should be processed when received. Return true to handle the push message yourself, false to let the SDK handle it internally.
  • showNotification(notification: ChatNotification): Shows notifications for different types of notifications. Supported types are: MessageNew, MessageUpdated, ReactionNew and NotificationReminderDue.
  • dismissChannelNotifications(channelType: String, channelId: String): Dismisses all notifications for a specific channel.
  • dismissAllNotifications(): Dismisses all notifications.
  • onNotificationPermissionStatus(status: NotificationPermissionStatus): Handles notification permission lifecycle.
class MyNotificationHandler(private val context: Context) : NotificationHandler {
    private val notificationManager: NotificationManager by lazy {
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    }

    override fun onNotificationPermissionStatus(status: NotificationPermissionStatus) {
        when (status) {
            NotificationPermissionStatus.REQUESTED -> {
                // invoked when POST_NOTIFICATIONS permission is requested
            }
            NotificationPermissionStatus.GRANTED -> {
                // invoked when POST_NOTIFICATIONS permission is granted
            }
            NotificationPermissionStatus.DENIED -> {
                // invoked when POST_NOTIFICATIONS permission is denied
            }
            NotificationPermissionStatus.RATIONALE_NEEDED -> {
                // invoked when POST_NOTIFICATIONS permission requires rationale
            }
        }
    }

    override fun showNotification(notification: ChatNotification) {
        when (notification) {
            is ChatNotification.MessageNew -> {
                // Handle new message notification
                // You can customize the notification here
            }
            is ChatNotification.ReactionNew -> {
                // Handle new reaction notification
                // You can customize the notification here
            }
            is ChatNotification.MessageUpdated -> {
                // Handle message updated notification
                // You can customize the notification here
            }
            is ChatNotification.NotificationReminderDue -> {
                // Handle reminder notification
                // You can customize the notification here
            }
        }
    }

    override fun dismissChannelNotifications(channelType: String, channelId: String) {
        // Dismiss all notification related with this channel
    }

    override fun dismissAllNotifications() {
        // Dismiss all notifications
    }
}

Finally, pass as the NotificationHandler implementation to the ChatClient.Builder when initializing the Stream Android SDK:

val notificationHandler = MyNotificationHandler(context)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()

Advanced Notification Configuration

The NotificationConfig class provides comprehensive control over push notification behavior. Here’s a detailed explanation of each property:

WebSocket Connection Behavior

ignorePushMessageWhenUserOnline: (type: String) -> Boolean Controls whether push notifications should be shown when the user has an active WebSocket connection. This allows you to customize behavior based on notification type.

Supported notification types:

  • ChatNotification.TYPE_MESSAGE_NEW - New message notifications
  • ChatNotification.TYPE_MESSAGE_UPDATED - Message updated notifications
  • ChatNotification.TYPE_REACTION_NEW - New message reaction notifications
  • ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE - Reminder notifications

Default behavior:

  • New message, message updated and reaction notifications are ignored when the user has an active WebSocket connection
  • Reminder notifications are always shown, even when the user has an active WebSocket connection
val notificationConfig = NotificationConfig(
    ignorePushMessageWhenUserOnline = { type ->
        when (type) {
            ChatNotification.TYPE_MESSAGE_NEW -> true // Ignore new messages when online
            ChatNotification.TYPE_MESSAGE_UPDATED -> true // Ignore message updates when online
            ChatNotification.TYPE_REACTION_NEW -> true // Ignore reactions when online
            ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE -> false // Always show reminders
            else -> true // Default behavior for unknown types
        }
    }
)

Runtime Notification Control

shouldShowNotificationOnPush: () -> Boolean = { true } Allows you to control whether notifications should be displayed after receiving a push message. This function is called for each push notification received and can be changed at runtime.

This is particularly useful when users want to temporarily disable notifications or when you need to implement custom logic based on your app’s internal state.

val notificationConfig = NotificationConfig(
    shouldShowNotificationOnPush = {
        // Custom logic to determine if notification should be shown
        // For example, only show notifications during certain hours
        val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
        currentHour in 8..22 // Only show notifications between 8 AM and 10 PM
    }
)

Permission Management

requestPermissionOnAppLaunch: () -> Boolean = { true } Controls whether the SDK should automatically request the POST_NOTIFICATIONS permission when the app launches. This is particularly important for Android 13+ where notification permission is required.

If you set this to false, you must handle the POST_NOTIFICATIONS permission request yourself. Otherwise, push notifications may not work properly on Android 13+ devices.
val notificationConfig = NotificationConfig(
    requestPermissionOnAppLaunch = {
        // Custom logic to determine if permission should be requested
        // For example, only request on first app launch
        isFirstAppLaunch()
    }
)

Advanced Features

autoTranslationEnabled: Boolean = false Enables or disables the auto-translation feature for push notifications. When enabled, notifications will be automatically translated based on the user’s language preferences.

val notificationConfig = NotificationConfig(
    autoTranslationEnabled = true // Enable automatic translation
)

Complete Configuration Example

Here’s a complete example showing how to configure all properties:

val notificationConfig = NotificationConfig(
    // WebSocket connection behavior
    ignorePushMessageWhenUserOnline = { type ->
        when (type) {
            ChatNotification.TYPE_MESSAGE_NEW -> true
            ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE -> false
            else -> true
        }
    },

    // Runtime notification control
    shouldShowNotificationOnPush = {
        val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
        currentHour in 8..22
    },

    // Permission management
    requestPermissionOnAppLaunch = { true },

    // Advanced features
    autoTranslationEnabled = true,
)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()

Dismissing notifications

Our MessageListView UI component and MessageList Compose UI Component automatically dismiss notifications related to a Channel when the user opens it.

If you need to dismiss them manually (for example, if you are using a custom MessageListView component) you can call the ChatClient::dismissChannelNotifications method, providing the channelType and channelId from the Channel that you would like to dismiss notifications:

ChatClient.instance().dismissChannelNotifications("messaging", "general")

Notifications are also automatically dismissed when the user logs out from the SDK.

Receiving Push Notifications with expired JWT token

A common scenario with short-lived Stream JWT tokens is receiving a push notification while the app is killed, and the Stream JWT token is already expired. In this case, the SDK cannot properly invoke the TokenProvider that you would pass via the ChatClient::connectUser method, because in a common use case, you would not automatically connect the user when receiving a push notification, thus the ChatClient will not have a registered TokenProvider (yet). The SDK however, must internally fetch some data from the Stream server to properly show the notification, and for this it needs a valid JWT token. To bypass this, the NotificationConfig class provides a tokenProvider property, that you can set at the time of building the ChatClient, without the need to call connectUser. This TokenProvider will be invoked only in this specific scenario, when the ChatClient attempts to load notification data with an expired JWT token, and the app still hasn’t called connectUser.

You can set this TokenProvider as follows:

val notificationConfig = NotificationConfig(
    tokenProvider = CustomTokenProvider(),
)
ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()
This TokenProvider is only used to retrieve a valid Stream JWT token when showing a push notification before the app has called ChatClient::connectUser. You still need to pass a valid TokenProvider when connecting the user via ChatClient::connectUser.

Unsubscribing from push notifications

If you want to permanently stop receiving push notifications on a device, you need to delete the device from the Stream backend. There are two ways to do this:

  • Automatic deletion: The deletion of the device can be done automatically when the user disconnects from the SDK. This is controlled by the deleteDevice parameter of the disconnect method:
// Setting deleteDevice to true will result in the
// device being deleted from Stream backend
ChatClient.instance()
    .disconnect(deleteDevice = true)
    .enqueue()
The deleteDevice flag is available since 6.26.0 of the SDK. In older versions of the SDK, the automatic deletion is controlled by the flushPersistence flag of the disconnect method. To delete the registered device from the Stream backend, you need to call: ChatClient.instance().disconnect(flushPersistence = true).enqueue()
  • Manual deletion: If you want to fully control when the device is deleted, you can manually delete the device by calling ChatClient::deleteDevice, providing the device ID (push token) you used when registering the device:
val device = Device(
    token = "your_push_token", // ex. Firebase/Huawei/Xiaomi token
    pushProvider = PushNotificationsProvider.FIREBASE, // or HUAWEI, XIAOMI
    pushProviderName = "your_push_provider_name",
)
ChatClient.instance()
    .deleteDevice(device)
    .enqueue()
© Getstream.io, Inc. All Rights Reserved.