App push in React Native
activeThis how-to wires the @binoban/react-native bridge into your app's push setup,
so Engage pushes are displayed and their delivery, taps, and dismissals reported.
The bridge is a thin wrapper over the native SDKs, so the underlying behaviour
matches Android and iOS.
Work through App push first — it covers the prerequisites, the
shape of the integration, and the source marker the examples below branch on.
1. Configure the Android notification appearance
The bridge reads the notification icon and channel from AndroidManifest.xml
meta-data. Add whichever you want to override inside <application>:
<meta-data
android:name="io.binoban.sdk.reactNative.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="io.binoban.sdk.reactNative.push_channel_id"
android:value="binoban_engage" />
<meta-data
android:name="io.binoban.sdk.reactNative.push_channel_name"
android:value="Updates" />
<meta-data
android:name="io.binoban.sdk.reactNative.push_channel_description"
android:value="Order and account updates" />
| Meta-data key | Default if absent |
|---|---|
…default_notification_icon | Your app icon. |
…push_channel_id | DEFAULT_NOTIFICATION_CHANNEL_ID |
…push_channel_name | General |
…push_channel_description | Empty. |
The same channel-importance rule applies as on native Android: the channel is
created at IMPORTANCE_HIGH, and an existing channel with that id is reused
as-is.
Declare POST_NOTIFICATIONS in the same manifest, and request it at runtime on
Android 13+ — without it nothing is displayed:
import { PermissionsAndroid, Platform } from 'react-native';
if (Platform.OS === 'android' && PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS) {
await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
);
}
2. Register the token
Take the token from whichever push library you use and pass it straight through:
import { useBinoban } from '@binoban/react-native';
const { setDeviceToken } = useBinoban();
// wherever your push library hands you a new or refreshed token
setDeviceToken(token);
On iOS this must be the FCM registration token, not the APNs device token — Binoban delivers through Firebase.
Refresh callbacks only fire when the token is generated or rotated, so an app that already used push has one in hand that will never be re-announced. Fetch it once at startup so those installs register too:
import messaging from '@react-native-firebase/messaging';
messaging().getToken().then(setDeviceToken);
messaging().onTokenRefresh(setDeviceToken);
setDeviceToken is safe to call repeatedly — registering the same token twice is
harmless.
3. Forward incoming messages
When your push library delivers a data message, hand the payload to the bridge. The SDK displays it and reports delivery:
import { useEffect } from 'react';
import messaging from '@react-native-firebase/messaging';
import { useBinoban } from '@binoban/react-native';
// Foreground: inside a component
const { notify } = useBinoban();
useEffect(() => {
const unsubscribe = messaging().onMessage(async (remoteMessage) => {
if (remoteMessage.data?.source === 'binoban') {
notify(remoteMessage.data);
} else {
// your own push handling
}
});
return unsubscribe;
}, [notify]);
onMessage fires only while the app is foregrounded. Binoban sends data-only
messages, so a message that arrives while the app is backgrounded reaches your
background handler instead — forward it there too, or those notifications never
appear.
The background handler runs outside the component tree, so useBinoban() is
not available there. Forward through the client createClient() returned instead,
which means keeping that client in its own module rather than inside a component:
// src/binoban.ts — one client, importable from anywhere
import { createClient } from '@binoban/react-native';
export const binobanClient = createClient({ /* … */ });
// index.js — registered before the app renders
import { AppRegistry } from 'react-native';
import messaging from '@react-native-firebase/messaging';
import { binobanClient } from './src/binoban';
import App from './src/App';
import { name as appName } from './app.json';
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
if (remoteMessage.data?.source === 'binoban') {
binobanClient.notify(remoteMessage.data);
} else {
// your own push handling
}
});
AppRegistry.registerComponent(appName, () => App);
Call setBackgroundMessageHandler outside your components and before
AppRegistry.registerComponent. A push delivered to a backgrounded or terminated
app has no component tree to run in, so registering it inside a useEffect
silently loses every backgrounded notification.
As on the other platforms, the
source check
is for your branch, not the SDK's safety — notify ignores non-Binoban payloads
by itself. Drop the check if this app receives no pushes other than Binoban's.
4. Handle taps
Subscribe for live interactions, and check once at startup for the tap that cold-started the app:
import { useEffect } from 'react';
import { useBinoban } from '@binoban/react-native';
const { onNotificationInteraction, getInitialNotificationInteraction } = useBinoban();
useEffect(() => {
// A tap that launched the app before JS was listening. Call once.
getInitialNotificationInteraction().then((interaction) => {
if (interaction?.uri) navigateTo(interaction.uri);
});
const sub = onNotificationInteraction((interaction) => {
if (interaction.type === 'CLICKED' && interaction.uri) {
navigateTo(interaction.uri);
}
// interaction.customData is the string map sent with the push
});
return () => sub.remove();
}, []);
Each interaction carries { notificationUuid, type, actionId, uri, customData, reason }, where type is DELIVERED | CLICKED | CLOSED | FAILED | OPENED. The
SDK's own tracking is preserved automatically.
5. iOS host forwarding
On Android nothing further is needed — interactions reach JS on their own.
On iOS the SDK never registers a UNUserNotificationCenterDelegate. Something
in your app must own that delegate and forward to the bridge — but if you use
@react-native-firebase/messaging, it already owns it through Firebase's
method swizzling, and you can skip this step. Handle it only when you took the
delegate yourself (swizzling disabled, or another library claimed it).
Forward from JS by passing each callback's payload through:
const {
didReceiveNotificationResponse,
willPresentNotification,
didReceiveRemoteNotification,
} = useBinoban();
willPresentNotification(userInfo); // reports `delivered`
didReceiveNotificationResponse(userInfo, actionId, dismissed); // `clicked` / `closed`
didReceiveRemoteNotification(userInfo); // displays a data push
userInfo is the notification's raw payload dictionary, actionId is the tapped
button's id (null for a body tap), and dismissed is true only on a swipe-away.
…or forward straight from a native AppDelegate to the SDK's Swift entry points
(onWillPresentForwarded, onDidReceiveForwarded,
onApplicationDidReceiveRemoteNotification, onNewToken) — see
App push on iOS. The
bridge still emits the interaction to JS either way. The three JS methods are
no-ops on Android.
As on native iOS, the SDK does not open URLs — read interaction.uri and route it.
Verify it worked
- Your next flushed batch carries a
bb_notification_registeredevent with the token. - Send a test campaign from the panel. The notification appears, and
bb_notification_deliveredfollows; tapping it producesbb_notification_clicked. On iOS, keep the app in the foreground for this check —deliveredis reported from the foreground-presentation callback.
See Push events for the full list.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Nothing is displayed on Android | POST_NOTIFICATIONS not granted, or a pre-existing channel with that id sits below IMPORTANCE_HIGH. |
| Nothing is displayed on iOS | Background Modes → Remote notifications is off, so iOS never wakes the app for a data-only message. |
| Only foreground pushes appear | setBackgroundMessageHandler is not forwarding to notify. |
| The token never registers | You passed the APNs device token instead of the FCM token on iOS. |
| Taps do nothing on iOS | Expected — the SDK does not open URLs there. Route interaction.uri in your handler. |
| Nothing reaches JS on iOS | The host is not forwarding its UNUserNotificationCenterDelegate callbacks — see step 5. |
Next steps
- App push on Android · App push on iOS
- React Native SDK reference — the full method surface.
- Push events — what gets emitted, and the payload keys.
- Web push — the browser equivalent.