Set Up Messaging Push Notifications for Android

With push notifications, your customers can be alerted about messaging activity even when they aren't viewing the conversation. When a rep sends a message, your customer receives a notification on their device.

This article applies to the following implementations:

UI SDK Core SDK
✅ ✅

Before you add code in your app for notifications, set up your Firebase project for notifications. Then follow Salesforce org setup instructions at Set Push Notifications for Enhanced In-App Chat.

Notifications don't appear under these circumstances.

  • The app isn't installed.
  • The device isn't online.
  • The conversation is already displayed in the foreground.

Passing Token to SDK

  1. Implement FirebaseMessagingService to receive notification information.

  2. When implementing the onNewToken method, call the CoreClient.provideDeviceToken(applicationContext, token) method. This method should only be called one time per token. See the provideDeviceToken reference documentation.

internal class FCMTokenService : FirebaseMessagingService() {
    private val supervisorJob = SupervisorJob()
    private val scope = CoroutineScope(Dispatchers.Main + supervisorJob)

    override fun onDestroy() {
        super.onDestroy()
        supervisorJob.cancel("Service destroyed")
    }

    override fun onNewToken(token: String) {
        scope.launch { CoreClient.provideDeviceToken(applicationContext, token) }
    }
}

Handling a Tap (Optional)

By default, when a user taps on the notification, your app launches to the launcher activity (typically this activity is set up as the MainActivity in your app). If you want to take them to the updated conversation, extract the conversation_id property, and then use that value to open the correct messaging conversation.

To handle an incoming notification when the app is in the foreground, implement the onMessageReceived method in the FirebaseMessagingService. The notification can be found in the notification payload of the remoteMessage. To learn more, see Handling messages in the Firebase documentation.

class FCMTokenService : FirebaseMessagingService() {
    private val supervisorJob = SupervisorJob()
    private val scope = CoroutineScope(Dispatchers.Main + supervisorJob)

    override fun onDestroy() {
        super.onDestroy()
        supervisorJob.cancel("Service destroyed")
    }

    override fun onNewToken(token: String) {
        scope.launch { CoreClient.provideDeviceToken(applicationContext, token) }
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {

        // Check if message contains a data payload
        val notificationID = Random().nextInt()
        val conversationID: UUID = UUID.fromString(remoteMessage.data["conversation_id"])
        val messageBody: String? = remoteMessage.notification?.body

        // Create config
        val coreConfig = CoreConfiguration.fromFile(this, "configFile.json")
        val uiConfig = UIConfiguration(coreConfig, conversationID)

        // Create intent to open conversation on tap
        val intent = UIClient.Factory.create(uiConfig).createOpenConversationIntent(this)
        val pendingIntent: PendingIntent = TaskStackBuilder.create(this).run {
            addNextIntentWithParentStack(intent)
            getPendingIntent(notificationID, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
        }

        // Construct notification
        val notification = NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
            .setSmallIcon(R.drawable.notifications_icon)
            .setContentTitle("Enhanced In-App Chat")
            .setContentText(messageBody)
            .setPriority(NotificationCompat.PRIORITY_MAX)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .build()

        // Issue notification
        with(NotificationManagerCompat.from(this)) {
            notify(notificationID, notification)
        }
    }
}

To handle an incoming notification when the app is in the background, capture the extra argument that was passed to the MainActivity as part of the intent.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // The conversationID is delivered in the extras of the intent
        // of the launcher Activity if app is backgrounded
        intent.extras?.getString("conversation_id")?.let { conversationID ->

            // Create config
            val coreConfig = CoreConfiguration.fromFile(this, "configFile.json")
            val uiConfig = UIConfiguration(coreConfig, UUID.fromString(conversationID))

            // Start chat activity
            UIClient.Factory.create(uiConfig).openConversationActivity(this)
        }
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
    }

    // ...
}

To learn more, see Handle notification messages in a backgrounded app in the Firebase documentation.