Testing Expo push notifications in development builds without production APNs/FCM credentials
0 reputation · 24 Dec 2022, 18:05 UTC
0 reputation · 24 Dec 2022, 18:05 UTC
Goal: verify that a development client built with expo-dev-client can receive a remote push notification via Expo’s push service without configuring production APNs or FCM credentials.
Constraints: iOS remote push requires a physical device, Android channel behavior may differ between Expo’s service and direct FCM, and push tokens are specific to the build type, so test tokens cannot be reused for production sends.
Yes. You can verify remote push delivery in a development build using Expo’s own push notification service; you do not need to upload your own APNs keys or FCM server keys.
expo push:send or POST to https://exp.host/--/api/v2/push/send, Expo forwards the message to the appropriate service using those credentials.Notifications.getExpoPushTokenAsync() is valid for the Expo push service regardless of whether the app is a development build, Expo Go, or a production build—provided the token matches the build type.new NotificationChannel(...)); Expo’s service does not create them, but it forwards any channelId you set to FCM unchanged.badge, sound, contentAvailable, etc., and they will be applied.Expo’s push service acts as a thin relay: it receives your JSON payload, adds the device‑specific token, and sends it to APNs/FCM using Expo’s own keys. Because the relay does not modify the alert title/body or most options, the behavior you see in a dev build mirrors what you would see in production, except for Android notification channels, which you must configure in the app itself.
Install the notifications plugin (if not already):
expo install expo-notificationsRequest permission and retrieve the Expo push token (run this once per device/install):
import * as Notifications from 'expo-notifications';
async function registerForPush() {
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') {
alert('Permission not granted');
return;
}
const token = await Notifications.getExpoPushTokenAsync();
console.log('Expo push token:', token.data);
// Send this token to your server or copy it for manual testing
}
Make sure Android notification channels exist (example code, run once on app start):
import { Platform } from 'react-native';
import * as Notifications from 'expo-notifications';
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
});
}
Send a test notification via Expo CLI (replace EXPO_PUSH_TOKEN with the token from step 2):
expo push:send --token EXPO_PUSH_TOKEN --title "Test" --body "Hello from Expo"
Or via curl:
curl -H "Content-Type: application/json" \
-X POST https://exp.host/--/api/v2/push/send \
-d '{
"to": "EXPO_PUSH_TOKEN",
"sound": "default",
"title": "Test",
"body": "Hello from Expo",
"data": { "extra": "value" }
}'
Verify receipt:
const notificationListener = Notifications.addNotificationReceivedListener((notification) => {
console.log('Received:', notification);
});
Inspect the API response – a successful send returns:
{ "data": { "status": "ok", "receipts": [ { "messageId": "...", "status": "ok" } ] } }
expo-notifications ≥ 0.16 provides reliable token retrieval and background handling in both development builds and Expo Go.Do you have a physical iOS device available for testing? If you are only using a simulator, iOS remote push tests will not work regardless of the steps above.
Use comments to ask for clarification. Post a solution as an answer.
33,275 reputation · 25 Dec 2022, 04:58 UTC
When testing push notifications with a development client (expo-dev-client), remember that iOS sandbox push notifications are delivered only to a physical device—not to a simulator—and they will not appear if the user has force‑quit the app (swiped it away) unless the payload includes contentAvailable: true and the app is allowed to run in the background. Android behaves similarly: a notification will be shown only if the app’s process is alive or the system can start it via the notification tap; otherwise the notification may be silently dropped. Verifying these conditions helps avoid false‑negative results during dev‑build testing.