Skip to main content
engage

App push on Android

active
Audience: developerUpdated 2026-07-27

This how-to wires the Binoban Native SDK into your Android app's Firebase Cloud Messaging setup, so Engage pushes are displayed and their delivery, taps, and dismissals reported.

Work through App push first — it covers the prerequisites, the shape of the integration, and the source marker the examples below branch on.

1. Declare and request permission

Android 13+ requires runtime permission before anything can be displayed. Without it the SDK reports a failed interaction instead of showing a notification.

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
// reflect the outcome in your UI
}
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)

On Android 12 and below the permission is granted implicitly.

2. Initialize in Application.onCreate

Initialize from Application, not an Activity — a push can arrive while your app is backgrounded or killed, and the SDK must be able to display it without any UI having started.

import android.app.Application
import io.binoban.sdk.core.Notification
import io.binoban.sdk.core.platform.notifier.notification.configuration.NotificationPlatformConfiguration

class MyApp : Application() {
override fun onCreate() {
super.onCreate()

Notification.initialize(
NotificationPlatformConfiguration.Android(
notificationIconResId = R.drawable.ic_notification,
notificationChannelData = NotificationPlatformConfiguration.Android.NotificationChannelData(
id = "binoban_engage",
name = "Updates",
description = "Order and account updates"
)
)
)
}
}
Channel importance cannot be raised later

The SDK creates this channel at IMPORTANCE_HIGH, which heads-up notifications require. If a channel with that id already exists, Android does not allow raising its importance — the SDK reuses it as-is and logs a warning. If your existing channel sits below IMPORTANCE_HIGH, use a fresh channel id here.

3. Forward FCM callbacks

import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import io.binoban.sdk.core.Notification

class MyFirebaseMessagingService : FirebaseMessagingService() {

override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)

if (message.data["source"] == "binoban") {
Notification.notify(message.data)
} else {
// your own push handling
}
}

override fun onNewToken(token: String) {
super.onNewToken(token)
Notification.refreshToken(token)
}
}

Register it in your manifest if you have not already:

<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

The source check is not there to protect the SDK — Notification.notify already drops non-Binoban payloads on its own, so calling it unconditionally is safe. The branch exists so that your else arm does not also fire for a Binoban push. If your service handles nothing but Binoban messages, call notify bare.

Notification.refreshToken works even when no SDK instance is live — the common case for a token delivered to a backgrounded app. It caches the registration and replays it on next launch.

Register the token you already have

onNewToken only fires when FCM generates a token — on a fresh install, or on rotation. An app that already uses FCM has a token in hand, and that callback will not fire again for existing installs. Fetch it once at startup so those devices register too:

FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
Notification.refreshToken(task.result)
}
}

refreshToken is safe to call repeatedly — registering the same token twice is harmless.

4. Taps and dismissals

Clicks, dismissals, and deep-link opening are handled for you. The SDK tracks the interaction and opens the notification's target — or the tapped action button's target — with no extra wiring.

To read the customData sent with a push, or to route the tap through your own navigation instead, register a handler. Subclass the default one and call super so the SDK's own tracking still fires:

import io.binoban.sdk.core.platform.notifier.notification.DefaultNotificationInteractionHandler
import io.binoban.sdk.core.platform.notifier.notification.NotificationInteraction
import io.binoban.sdk.core.platform.notifier.notification.NotificationInteractionManager

class MyNotificationHandler : DefaultNotificationInteractionHandler() {
override fun onNotificationInteraction(interaction: NotificationInteraction) {
super.onNotificationInteraction(interaction) // keep SDK tracking

val deepLink = interaction.uri // tapped body or button target
val data = interaction.customData // your push customData, or null
// route as your app sees fit
}
}

// once, at startup:
NotificationInteractionManager.setHandler(MyNotificationHandler())

interaction.uri resolves to the tapped button's target when a button was pressed, or the notification's main target for a body tap.

Verify it worked

  1. Your next flushed batch carries a bb_notification_registered event with the token.
  2. Send a test campaign from the panel. The notification appears, and bb_notification_delivered follows; tapping it produces bb_notification_clicked.

See Push events for the full list.

Troubleshooting

SymptomLikely cause
Nothing is displayedPOST_NOTIFICATIONS not granted — the SDK reports a failed interaction with reason notification permission. Or a pre-existing channel with that id sits below IMPORTANCE_HIGH.
Messages arrive but nothing showsNotification.notify is not being called, or it runs before initialize.
Existing installs never registerOnly onNewToken is wired. It does not fire for a device that already had a token — fetch it once at startup as well.
Your own pushes get displayed twiceYour handler's else arm is also running for Binoban messages. Branch on source.

Next steps