Skip to content

Instantly share code, notes, and snippets.

@kibolho
Last active May 29, 2024 22:36
Show Gist options
  • Select an option

  • Save kibolho/d803757b381f4f600ad04bb0bdf08d66 to your computer and use it in GitHub Desktop.

Select an option

Save kibolho/d803757b381f4f600ad04bb0bdf08d66 to your computer and use it in GitHub Desktop.
Handle Notification on React Native using expo
// 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,
},
});
}
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