Set up push in React Native, Expo and Flutter
Use the Firebase messaging package your framework already has, register the token with SignOps, and send to Android and iOS from one call.
React Native, Expo and Flutter apps use the Firebase or Expo package they already have to get a token. Your server adds that token to SignOps, and one call sends to Android and iOS. The SignOps SDK is not needed for push.
Before you start, do the account half of the native guides, which is the same for every framework:
- Android: a Firebase project with your Android app, and its service account uploaded under Push, Setup, Android (Android guide, steps 1 and 5).
- iOS: an APNs
.p8key (iOS guide, step 1), and the Push Notifications capability in Xcode (step 4).
Which token each setup gives
| Framework and package | Android token | iOS token | iOS route in SignOps |
|---|---|---|---|
React Native with @react-native-firebase/messaging |
FCM | FCM | Through Firebase (upload the .p8 to Firebase) |
Flutter with firebase_messaging |
FCM | FCM | Through Firebase (upload the .p8 to Firebase) |
Expo with expo-notifications, getDevicePushTokenAsync |
FCM | APNs | Straight to Apple (upload the .p8 to SignOps) |
Set the route under Push, Setup, iOS before your first iPhone registers.
React Native
npm install @react-native-firebase/app @react-native-firebase/messaging
cd ios && pod install
Put google-services.json in android/app/ and GoogleService-Info.plist in the iOS project (both from the Firebase console, one app each). Then, after sign-in:
import messaging from "@react-native-firebase/messaging";
import { PermissionsAndroid, Platform } from "react-native";
export async function turnOnPush() {
if (Platform.OS === "android" && Platform.Version >= 33) {
await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
}
await messaging().requestPermission(); // iOS asks here; Android returns at once
const token = await messaging().getToken();
await api.saveDevice({ token, platform: Platform.OS }); // "android" or "ios"
messaging().onTokenRefresh((t) => api.saveDevice({ token: t, platform: Platform.OS }));
}
Expo
Expo push tokens (ExponentPushToken[...]) only work with Expo’s service. Ask for the phone’s own token instead:
import * as Notifications from "expo-notifications";
import { Platform } from "react-native";
export async function turnOnPush() {
const { status } = await Notifications.requestPermissionsAsync();
if (status !== "granted") return;
const { data: token } = await Notifications.getDevicePushTokenAsync(); // FCM on Android, APNs on iOS
await api.saveDevice({ token, platform: Platform.OS });
}
In app.json, set android.googleServicesFile to your google-services.json, then make a development build (npx expo prebuild, or EAS Build). Expo Go cannot use your own Firebase project. If pushes worked in development and stopped in the APK, see Expo push notifications not working. A runnable app and server: expo-push on GitHub.
Flutter
flutter pub add firebase_core firebase_messaging
dart pub global activate flutterfire_cli
flutterfire configure # adds Android and iOS apps to your Firebase project
In Xcode (ios/Runner.xcworkspace), add the Push Notifications capability to the Runner target. Then, after sign-in:
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
Future<void> turnOnPush() async {
final fm = FirebaseMessaging.instance;
await fm.requestPermission(); // iOS and Android 13 and later
final token = await fm.getToken();
final platform = Platform.isIOS ? 'ios' : 'android';
if (token != null) await api.saveDevice(token, platform);
fm.onTokenRefresh.listen((t) => api.saveDevice(t, platform));
}
Your server, for all three
api.saveDevice is your own endpoint. It knows the signed-in user and adds the token:
// Node, with npm install @signops/node
import { SignOps } from "@signops/node";
const signops = new SignOps(process.env.SIGNOPS_KEY);
app.post("/api/devices", requireUser, async (req, res) => {
const device = await signops.devices.add({ user_id: req.user.id, platform: req.body.platform, token: req.body.token });
res.json({ id: device.id }); // keep it, to remove the device when the user signs out
});
// Later, from anywhere on your server
await signops.push.send({ user_id: "usr_8f21c4", title: "Your order is out for delivery", body: "Ravi is 10 minutes away." });
Then send a test from Push, Setup in the dashboard with the user id, or with the call above, and check Push, Messages for what Google and Apple said.
Using Approve or passkeys too
Those need the SignOps module in the app (@signops/react-native or the signops Flutter plugin), which reuses the Firebase token you already have. It is not on npm or pub.dev yet; see the Approve guide for what it does and the calls it makes.