Push notification
Initialize the SDK
When using JavaScript-controlled initialization, call initialize() before registering listeners or requesting push notifications:
import Reteno from 'expo-reteno-sdk';
await Reteno.initialize('YOUR_SDK_ACCESS_KEY');Skip this call if sdkAccessToken is set in the platform plugin config, because that enables automatic initialization.
Register for push notifications
Call registerForRemoteNotifications() once at app startup:
import { useEffect } from 'react';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
Reteno.registerForRemoteNotifications();
}, []);Get initial notification
When your app is opened by clicking a push notification, you can read its payload with getInitialNotification.
import { useEffect } from 'react';
import { Alert } from 'react-native';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
Reteno.getInitialNotification().then((data) => {
Alert.alert('getInitialNotification', data ? JSON.stringify(data) : 'null');
});
}, []);Listen for new push notifications while app is active
To listen to pushes in foreground, use setOnRetenoPushReceivedListener:
import { useEffect } from 'react';
import { Alert } from 'react-native';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
const pushListener = Reteno.setOnRetenoPushReceivedListener((event) => {
Alert.alert('onRetenoPushReceived', event ? JSON.stringify(event) : 'null');
});
return () => pushListener.remove();
}, []);Listen for Push Notification Clicks
To handle notification clicks, use setOnRetenoPushClickedListener:
import { useEffect } from 'react';
import { Alert } from 'react-native';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
const pushClickListener = Reteno.setOnRetenoPushClickedListener((event) => {
Alert.alert('onRetenoPushClicked', event ? JSON.stringify(event) : 'null');
});
return () => pushClickListener.remove();
}, []);iOS Action Buttons
For iOS push action buttons, use setOnRetenoPushButtonClickedListener:
import { useEffect } from 'react';
import { Platform } from 'react-native';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
if (Platform.OS !== 'ios') return;
const listener = Reteno.setOnRetenoPushButtonClickedListener((event) => {
console.log('onRetenoPushButtonClicked', event);
});
return () => listener.remove();
}, []);Set device token manually
Use setDeviceToken() when managing the iOS FCM/APNs token manually:
const result = await Reteno.setDeviceToken(token);The method returns Promise<boolean>. On Android it resolves successfully without changing the token because token handling is performed by the native Firebase messaging service.
Listen for Push Notification Dismissed (Android only)
To handle when a user dismisses a push notification, use setOnRetenoPushDismissedListener:
import { useEffect } from 'react';
import { Platform } from 'react-native';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
if (Platform.OS !== 'android') return;
const listener = Reteno.setOnRetenoPushDismissedListener((event) => {
console.log('onRetenoPushDismissed', event);
});
return () => listener?.remove();
}, []);Listen for Custom / Silent Push Data (Android only)
To receive custom or silent push payloads, use setOnRetenoCustomPushDataListener:
import { useEffect } from 'react';
import { Platform } from 'react-native';
import Reteno from 'expo-reteno-sdk';
useEffect(() => {
if (Platform.OS !== 'android') return;
const listener = Reteno.setOnRetenoCustomPushDataListener((event) => {
console.log('onRetenoCustomPushReceived', event);
});
return () => listener?.remove();
}, []);Notification Permission (Android only)
Request notification permission at runtime and check its status:
import { Platform } from 'react-native';
import Reteno from 'expo-reteno-sdk';
// Request permission
if (Platform.OS === 'android') {
const isGranted = await Reteno.requestNotificationPermission();
console.log('Permission granted:', isGranted);
}
// Check current status
if (Platform.OS === 'android') {
const status = await Reteno.getNotificationPermissionStatus();
// status: 'ALLOWED' | 'DENIED' | 'PERMANENTLY_DENIED' | null
console.log('Permission status:', status);
}Group notifications (Android only)
Requires Reteno Android SDK 2.10.0 or newer (bundled since
expo-reteno-sdkv2.2.0).
Notifications can be grouped by a value in the push payload or by a constant group ID. The rule is persisted natively and restored before JavaScript starts, so it also applies to notifications received while the app is not running.
import Reteno from 'expo-reteno-sdk';
// Group by a payload value, e.g. all pushes for the same chat
await Reteno.setNotificationGroupingRule({ payloadKey: 'chatId' });
// Group under a constant ID, regardless of payload
await Reteno.setNotificationGroupingRule({ groupId: 'messages' });
// Also show the collapsed "N new notifications" summary row Android displays
// when it stacks the group
await Reteno.setNotificationGroupingRule({ groupId: 'messages', showSummary: true });
// Disable grouping
await Reteno.setNotificationGroupingRule(null);The rule must contain exactly one non-empty payloadKey or groupId.
Summary notification (showSummary)
showSummary)Requires
expo-reteno-sdkv2.3.0or newer.
Pass showSummary: true to also get the collapsed "N new notifications" row Android shows when it stacks a group. The SDK creates and maintains this summary notification for you natively ā no native code or manual NotificationCompat setup needed. It:
- creates a dedicated
reteno_group_summarynotification channel (Android 8.0+), - posts/updates the summary once at least two notifications share a group, using the fixed text "New notifications" / "You have N new notifications" (not currently customizable),
- removes the summary once fewer than two grouped notifications remain, e.g. after the user dismisses one down to a single leftover,
- automatically clears any existing summary if you call
setNotificationGroupingRuleagain with a differentpayloadKey/groupId.
Requires Android 6.0 (API 23) or higher ā on older devices the call still resolves successfully and grouping still applies, but no summary is shown. Like any notification, posting the summary also requires the POST_NOTIFICATIONS runtime permission on Android 13+ (see Notification Permission (Android only) above); if it isn't granted, the summary is silently skipped until permission is granted and the next push arrives.
Upgrading from a manual summary implementation? Earlier versions of this guide showed how to
post the summary yourself fromMainApplication.ktusing
RetenoNotificationGroupingRuleProvider.resolveGroup(...). That helper is no longer part of the
public API inv2.3.0ā delete that native code and passshowSummary: trueinstead.
Auto-open links behavior
Use these methods to control whether SDK opens links from push/in-app automatically:
import Reteno from 'expo-reteno-sdk';
await Reteno.setAutoOpenLinks(true); // enable
const isEnabled = await Reteno.getAutoOpenLinks();
console.log('Auto-open links:', isEnabled);Default value:
- iOS:
true - Android:
false
Important for Expo
expo-reteno-sdkrequires a development build or bare app.- Expo Go is not supported for push features using native module integration.