Today we are going to implement PUSH notifications in Android/iOS for React Native using the Expo Notifications library.
First, we will install the required libraries:
npm install expo-install-expo-notifications expo-install-expo-device expo-install-expo-constants
Once installed we will use this code which also generates two types of tokens:
import { Notifications } from 'expo-notifications'; import { Device } from 'expo-device'; import { Platform } from 'react-native'; import Constants from 'expo-constants'; export enum PushTokenType { Expo = 'expo', Fcm = 'fcm', } /** * Requests permissions for notifications from the user. * @param tokenType PushTokenType.Expo -> ExponentPushToken[...] (uses Expo Push API) * PushTokenType.Fcm -> native FCM/APNs token (compatible with your backend actual) */ export async function requestUserNotificationsPermission(tokenType: PushTokenType = PushTokenType.Expo): Promise { try { if (!Device.isDevice) { console.log('Push notifications require a physical device'); return "-1"; } const { status: existingStatus } = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { const { status } = await Notifications.requestPermissionsAsync(); finalStatus = status; } const enabled = finalStatus === 'granted'; console.log('User granted permission: ', enabled); if (Platform.OS === 'android') { await Notifications.setNotificationChannelAsync('default', { name: 'default', importance: Notifications.AndroidImportance.MAX, }); } if (!enabled) { return "-1"; } switch (tokenType) { case PushTokenType.Expo: return await GetExpoPushToken(); case PushTokenType.Fcm: return await GetFCMToken(); default: return "-1"; } } catch (error) { console.log('Error in requestUserNotificationsPermission: ', error); return "-1"; } } /** * Token format ExponentPushToken[xxxxxxxxxxxx] * For use with the Expo Push API (https://exp.host/--/api/v2/push/send) */ export async function GetExpoPushToken(): Promise { try { const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId; if (!projectId) { throw new Error('No found the projectId of EAS (check app.json/app.config)'); } const tokenResponse = await Notifications.getExpoPushTokenAsync({ projectId }); return tokenResponse.data; } catch (error) { console.log('Error getting Expo push token: ', error); return "-1"; } } /** * Native token (FCM in Android, APNs in iOS) * Same format as already stored, for continued use with your backend/FCM directly */ export async function GetFCMToken(): Promise { try { const tokenResponse = await Notifications.getDevicePushTokenAsync(); return tokenResponse.data; } catch (error) { console.log('Error getting device push token: ', error); return "-1"; } }
Token formats:
getExpoPushTokenAsync() → token format ExponentPushToken[...], thought for use with the Expo Push Service. The old FCM tokens do not work here you will have to go back and ask for permission/register each device to get new tokens in this format. There is no way to «convert» an FCM token to Expo token without re-registering the device.
getDevicePushTokenAsync() returns the native token (FCM on Android, APNs on iOS).
And usage:
//Notification Token: try { const tokenNotifications = await requestUserNotificationsPermission(PushTokenType.Expo); if (tokenNotifications && tokenNotifications !== "-1") { ... SEND TO SERVER FOR EXAMPLE... } else { console.log("Could not get the notification token"); } } catch (error) { console.log("Error getting notification token:", error); // You can choose to continue or show a warning }
