├ 06
react native
React Native gives you three paths. Pick the one matching your project shape, and if you're an Expo user, read the callout below carefully because there's exactly one trap you need to avoid.
Bare RN with @react-native-firebase/messaging
import messaging from "@react-native-firebase/messaging";
export async function setupPush() {
const status = await messaging().requestPermission();
if (
status === messaging.AuthorizationStatus.DENIED ||
status === messaging.AuthorizationStatus.NOT_DETERMINED
) return;
const fcmToken = await messaging().getToken();
await sendTokenToServer({ platform: "fcm", token: fcmToken });
messaging().onTokenRefresh((newToken) => {
sendTokenToServer({ platform: "fcm", token: newToken });
});
}Expo (managed or bare) with expo-notifications
import * as Notifications from "expo-notifications";
export async function setupPush() {
const { status } = await Notifications.requestPermissionsAsync();
if (status !== "granted") return;
// DEVICE token = native APNs hex / FCM token (use this with edgepush)
// EXPO token = "ExponentPushToken[...]" (only Expo's Push Service)
const token = await Notifications.getDevicePushTokenAsync();
await fetch("https://your.api/register-token", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
platform: token.type,
token: token.data,
}),
});
}● the one expo trap
Most Expo Notifications tutorials lead with getExpoPushTokenAsync(). That returns an ExponentPushToken[xxx] wrapper that onlyExpo's Push Service understands. It is not a native APNs or FCM token.
edgepush wants the real one. Always use getDevicePushTokenAsync() instead. That's the entire client-side migration step from Expo Push to edgepush, change one function name.