This guide shows how to add push notifications in Expo, but without expo-notifications. Nothing against expo-notifications, it's just that I learned this method first.
Expo GO will not work. This is always the case when you use native modules. Use dev client instead.
iOS Setup
You need to setup APN (Apple Push Notification), go to Apple Developer -> Certificates, Identifiers & Profiles, find your app's identifier and enable Push Notifications under Capabilities.
Enable Broadcast Capability if you want to send to multiple users at once.
Ignore the Configure button, that's just legacy.
Save, and go to Keys in Certificates, Identifiers & Profiles. Create an APNs Authentication Key.
Enable Apple Push Notifications service (APNs), click the Configure/Edit in the right and choose environments, Sandbox + Production seems easiest.

Save. If you reach the:
You have already reached the maximum allowed number of team scoped Keys
Then you already have some keys created for this. You only need one key and you can reuse it in other apps.
If all is ok, then download the p8 file and remember the key id.
You need to recreate the provisioning profile. Recreate it with "eas credentials -p ios", choose iOS, select "Build Credentials", choose your target.
Then select the first option to setup all build credentials. cli will ask you if you want to "Generate a new Apple Provisioning Profile?", select yes.
Now go to firebase console, go to Project Settings, select Cloud Messaging tab. If it is not enabled, enable it. Find your app package and upload the APNs Authentication Key, the p8 file I instructed you to create.

Download google service plist in the root of your app directory. Check that expo app config points to google plist file.
Android Setup
Android uses firebase cloud messaging. You need to enter all the necessary sha-1 or sha-256 fingerprints in project settings -> General -> scroll down to Android settings. If you have enabled google login, then you already have that part covered. Just read through the configuring sha fingerprints.
Download google service files in the root of your app directory. Check that expo app config points to google service files.
Code Setup
Install dependencies
npx expo install @react-native-firebase/messaging react-native-permissions
For iOS, edit app config file and check that it includes these settings:
const config: ExpoConfig = {
ios: {
entitlements: {
'aps-environment': process.env.NODE_ENV !== 'production' ? 'development' : 'production',
},
infoPlist: {
// Optional, if you want ios silent push notifications
UIBackgroundModes: ['remote-notification'],
},
},
android: {
permissions: ['android.permission.POST_NOTIFICATIONS']
},
plugins: [
['react-native-permissions', { iosPermissions: ['Notifications'] }]
]
}
Ask for Permission
You need to ask the user to allow push notifications on his device.
import {
checkNotifications,
requestNotifications,
type PermissionStatus,
type NotificationsResponse,
} from 'react-native-permissions';
export const useNotificationPermission = () => {
const [notificationResponse, setNotificationResponse] = useState<NotificationsResponse | null>(null);
const [isRequesting, setIsRequesting] = useState(false);
const refresh = useCallback(async (): Promise<void> => {
const res = await checkNotifications();
setNotificationResponse(res);
}, []);
const request = useCallback(async (): Promise<PermissionStatus> => {
setIsRequesting(true);
try {
const res = await requestNotifications(['alert', 'badge', 'sound']);
setNotificationResponse(res);
return res.status;
} finally {
setIsRequesting(false);
}
}, []);
useEffect(() => {
request()
.then((response) => {
console.debug('Notification request request - ', response);
})
.catch((err) => console.debug('Failed to refresh notification permissions', err));
}, []);
useEffect(() => {
refresh().catch((err) => console.debug('Failed to refresh notification permissions', err));
const onChange = (next: AppStateStatus) => {
if (next === 'active') {
refresh().catch((err) => console.debug('Failed to refresh notification permissions', err));
}
};
const sub = AppState.addEventListener('change', onChange);
return () => sub.remove();
}, [refresh]);
return {
status: notificationResponse?.status,
isRequesting,
request,
};
};
This hook checks and requests permissions in iOS or Android app. I have also added a listener when the app becomes active. Usually users don't fully exit their apps and I want to update the state if the user updated permissions in the meantime.
Request Device Token
Device Tokens are addresses to which one can send push notifications.
After the user has allowed push notifications, we can request their device token using firebase messaging service:
import messaging from '@react-native-firebase/messaging';
import { useEffect, useState } from 'react';
import { useNotificationPermission } from '@/src/hooks/useNotificationPermission';
export function useDeviceToken() {
const permission = useNotificationPermission();
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
if (permission.status !== 'granted') {
console.warn('Notification permission not granted, cannot fetch FCM token');
return;
}
void (async () => {
try {
await messaging().registerDeviceForRemoteMessages();
console.debug('APNs token:', await messaging().getAPNSToken());
const fcm = await messaging().getToken();
console.debug('FCM token:', fcm);
setToken(fcm);
} catch (e) {
console.warn('FCM init failed:', e);
}
})();
return messaging().onTokenRefresh(setToken);
}, [permission.status]);
return token;
}
See that I also log APNs token. You'll need that if you want to test notifications with iOS cloud utility.
Send Test Push Notification
Send test push notification on iOS by going to https://icloud.developer.apple.com/dashboard/notifications/teams/, select your app and send a test push notification.
You will only get to see that alert if you exit your app, or if your app is not in the focus.
If you want to test Android, you will have to use fcm. Go to firebase console, select cloud messaging service (not the one in project settings), and select to send a new push notification message.
You will see a "Send test message" button. Select it and add your FCM token. With this UI utility, you can test sending push notification to either Android or iOS apps.
Next Steps
I covered the basics, making push notifications work on Android and iOS. One of the next steps could be making it work on react native web, saving device tokens on your server, adding a foreground listener, sending targeted push notifications...Stay tuned.