Last active
May 29, 2024 22:36
-
-
Save kibolho/d803757b381f4f600ad04bb0bdf08d66 to your computer and use it in GitHub Desktop.
Handle Notification on React Native using expo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // How to use it: | |
| const authenticate = ({login, password}: {login:string; password:string)=> { | |
| const pushToken = await Storage.get(StorageKeys.PUSH_TOKEN); | |
| return httpClient.request({ | |
| url: API_ROUTES.AUTH, | |
| method: 'post', | |
| body: { | |
| login, | |
| password, | |
| pushToken: pushToken, | |
| }, | |
| }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import messaging, { FirebaseMessagingTypes } from '@react-native-firebase/messaging'; | |
| import * as Notifications from 'expo-notifications'; | |
| import { router } from 'expo-router'; | |
| import React, { createContext, useContext, useEffect } from 'react'; | |
| import { Linking, PermissionsAndroid, Platform } from 'react-native'; | |
| import { usePlatforms } from './platformsProvider'; | |
| import useLocalStorage from '@/hooks/useLocalStorage'; | |
| import { StorageKeys } from '@/infra/storage/storageKeys'; | |
| import observability from '@/lib/observability'; | |
| // Set up the notification handler for the app | |
| Notifications.setNotificationHandler({ | |
| handleNotification: async () => ({ | |
| shouldShowAlert: true, | |
| shouldPlaySound: true, | |
| shouldSetBadge: false, | |
| }), | |
| }); | |
| const defaultRouteAfterNotification = '/(tabs)/timeline'; | |
| const NotificationContext = createContext< | |
| | { | |
| pushToken: string | undefined; | |
| } | |
| | undefined | |
| >(undefined); | |
| export const NotificationProvider: React.FC<React.PropsWithChildren> = ({ children }) => { | |
| const [pushToken, setPushToken] = useLocalStorage(StorageKeys.PUSH_TOKEN); | |
| const { installedPlatforms } = usePlatforms(); | |
| const requestUserPermission = async () => { | |
| if (Platform.OS === 'ios') { | |
| const authStatus = await messaging().requestPermission(); | |
| const enabled = | |
| authStatus === messaging.AuthorizationStatus.AUTHORIZED || | |
| authStatus === messaging.AuthorizationStatus.PROVISIONAL; | |
| return enabled; | |
| } else { | |
| return PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS); | |
| } | |
| }; | |
| const setupNotification = async () => { | |
| const enabled = await requestUserPermission(); | |
| if (enabled) { | |
| messaging() | |
| .getToken() | |
| .then((token) => { | |
| setPushToken(token); | |
| }) | |
| .catch((error) => { | |
| observability.captureException(error); | |
| }); | |
| } | |
| }; | |
| const handleRemoteMessage = (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => { | |
| if (typeof remoteMessage?.data?.url === 'string') { | |
| Linking.openURL(remoteMessage.data.url); | |
| } | |
| if (remoteMessage?.data?.screen) { | |
| router.replace(`${remoteMessage.data.screen}`); | |
| } | |
| router.replace(defaultRouteAfterNotification); | |
| }; | |
| useEffect(() => { | |
| setupNotification(); | |
| // Handle user opening the app from a notification (when the app is in the background) | |
| messaging().onNotificationOpenedApp((remoteMessage) => { | |
| console.log( | |
| 'Notification caused app to open from background state:', | |
| remoteMessage?.data?.screen | |
| ); | |
| handleRemoteMessage(remoteMessage); | |
| }); | |
| // Check if the app was opened from a notification (when the app was completely quit) | |
| messaging() | |
| .getInitialNotification() | |
| .then((remoteMessage) => { | |
| if (remoteMessage) { | |
| console.log( | |
| 'Notification caused app to open from quit state:', | |
| remoteMessage.notification | |
| ); | |
| handleRemoteMessage(remoteMessage); | |
| } | |
| }); | |
| const platformNotificationItsOnline = async (remotePlatform: string) => { | |
| if ( | |
| !installedPlatforms || | |
| Object.keys(installedPlatforms).length <= 0 || | |
| installedPlatforms === null | |
| ) { | |
| return true; | |
| } | |
| try { | |
| return Object.entries(installedPlatforms).some(([platform, config]) => { | |
| return remotePlatform === platform && config.notification === true; | |
| }); | |
| } catch (error) { | |
| console.error(error); | |
| } | |
| }; | |
| // Handle push notifications when the app is in the background | |
| messaging().setBackgroundMessageHandler(async (remoteMessage) => { | |
| console.log('Message handled in the background!', remoteMessage); | |
| const notification = { | |
| title: remoteMessage?.notification?.title, | |
| body: remoteMessage?.notification?.body, | |
| data: remoteMessage.data, | |
| sound: 'notificationcash.wav', | |
| }; | |
| const remotePlatform = notification?.data?.source?.toString() ?? ''; | |
| const notificationItIsOnline = await platformNotificationItsOnline(remotePlatform); | |
| if (!notificationItIsOnline) return; | |
| // Schedule the notification with a null trigger to show immediately | |
| await Notifications.scheduleNotificationAsync({ | |
| content: notification, | |
| trigger: null, | |
| }); | |
| }); | |
| // Handle push notifications when the app is in the foreground | |
| const handlePushNotification = async (remoteMessage: any) => { | |
| const notification = { | |
| title: remoteMessage.notification?.title, | |
| body: remoteMessage.notification?.body, | |
| data: remoteMessage.data, | |
| sound: 'notificationcash.wav', | |
| }; | |
| const remotePlatform = notification?.data?.source?.toString() || ''; | |
| const notificationItIsOnline = await platformNotificationItsOnline(remotePlatform); | |
| if (!notificationItIsOnline) return; | |
| // Schedule the notification with a null trigger to show immediately | |
| await Notifications.scheduleNotificationAsync({ | |
| content: notification, | |
| trigger: null, | |
| }); | |
| }; | |
| // Listen for push notifications when the app is in the foreground | |
| const unsubscribe = messaging().onMessage(handlePushNotification); | |
| // Clean up the event listeners | |
| return () => { | |
| unsubscribe(); | |
| }; | |
| }, []); | |
| return ( | |
| <NotificationContext.Provider | |
| value={{ | |
| pushToken, | |
| }}> | |
| {children} | |
| </NotificationContext.Provider> | |
| ); | |
| }; | |
| export const useNotification = () => { | |
| const context = useContext(NotificationContext); | |
| if (context === undefined) { | |
| throw new Error('useNotification must be used within a NotificationProvider'); | |
| } | |
| return context; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment