Untitled
unknown
plain_text
14 days ago
7.4 kB
3
Indexable
import messaging from '@react-native-firebase/messaging'; import { Platform } from 'react-native'; import * as Device from 'expo-device'; export class FirebaseMessagingService { private static instance: FirebaseMessagingService; private _fcmToken: string | null = null; private constructor() {} static getInstance(): FirebaseMessagingService { if (!FirebaseMessagingService.instance) { FirebaseMessagingService.instance = new FirebaseMessagingService(); } return FirebaseMessagingService.instance; } /** * Request permission to receive push notifications */ async requestPermission(): Promise<boolean> { if (!Device.isDevice) { console.log('Must use physical device for Push Notifications'); return false; } try { const authStatus = await messaging().requestPermission(); const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED || authStatus === messaging.AuthorizationStatus.PROVISIONAL; if (enabled) { console.log('Firebase messaging authorization status:', authStatus); return true; } else { console.log('Firebase messaging authorization denied'); return false; } } catch (error) { console.error('Error requesting notification permission:', error); return false; } } /** * Get the FCM token for this device */ async getFCMToken(): Promise<string | null> { try { // Always clear the cached token to force a fresh attempt this._fcmToken = null; console.log('Platform:', Platform.OS); // For iOS, we need to register for remote messages before getting the token if (Platform.OS === 'ios') { try { // Force iOS to use the sandbox APNs environment for development builds if (__DEV__) { console.log('Setting up Firebase Messaging for development (sandbox APNs)'); // This is a workaround to force Firebase to use the sandbox APNs environment // It's not officially documented but might help in some cases const messagingInstance = messaging(); (messagingInstance as any)._useSandbox = true; } console.log('iOS: Checking if already registered for remote messages'); const isRegistered = await messaging().isDeviceRegisteredForRemoteMessages; console.log('iOS: Device registered status:', isRegistered); // Always force re-registration to ensure we have the latest registration console.log('iOS: Registering device for remote messages'); await messaging().registerDeviceForRemoteMessages(); console.log('iOS: Device successfully registered for remote messages'); // Wait for APNs token to be available console.log('iOS: Checking for APNs token...'); const apnsToken = await messaging().getAPNSToken(); console.log('iOS: APNs token:', apnsToken || 'Not available'); if (!apnsToken) { console.warn('iOS: No APNs token available'); } } catch (registerError) { console.error('Error registering for remote messages:', registerError); if (registerError instanceof Error) { console.error('Error message:', registerError.message); console.error('Error stack:', registerError.stack); } throw registerError; } } console.log('Getting FCM token...'); // Get the token const token = await messaging().getToken(); console.log('FCM Token received:', token ? 'Yes (length: ' + token.length + ')' : 'No'); this._fcmToken = token; return token; } catch (error) { console.error('Error getting FCM token:', error); if (error instanceof Error) { console.error('Error message:', error.message); console.error('Error stack:', error.stack); } return null; } } /** * Register for foreground notifications * @param callback Function to call when a notification is received in foreground */ onForegroundMessage(callback: (message: any) => void) { console.log('Setting up Firebase foreground message handler'); return messaging().onMessage((message) => { console.log('Firebase message received in foreground:', message); callback(message); }); } /** * Register for background notifications * This must be called outside of any component * @param callback Function to call when a notification is received in background */ static setBackgroundMessageHandler(callback: (message: any) => Promise<void>) { console.log('Setting up Firebase background message handler'); messaging().setBackgroundMessageHandler(async (message) => { console.log('Firebase message received in background:', message); return callback(message); }); } /** * Register for notification open events * @param callback Function to call when a notification is opened */ onNotificationOpen(callback: (message: any) => void) { return messaging().onNotificationOpenedApp(callback); } /** * Check if the app was opened from a notification */ async getInitialNotification() { return await messaging().getInitialNotification(); } /** * Subscribe to a topic * @param topic Topic to subscribe to */ async subscribeToTopic(topic: string): Promise<void> { try { await messaging().subscribeToTopic(topic); console.log(`Subscribed to topic: ${topic}`); } catch (error) { console.error(`Error subscribing to topic ${topic}:`, error); } } /** * Unsubscribe from a topic * @param topic Topic to unsubscribe from */ async unsubscribeFromTopic(topic: string): Promise<void> { try { await messaging().unsubscribeFromTopic(topic); console.log(`Unsubscribed from topic: ${topic}`); } catch (error) { console.error(`Error unsubscribing from topic ${topic}:`, error); } } /** * Configure the notification channel for Android * This is required for Android 8.0+ */ async createAndroidChannel(): Promise<void> { if (Platform.OS === 'android') { try { // For Firebase, we'll use the Expo Notifications API to create a channel // that will be used by Firebase notifications const { Notifications } = require('expo-notifications'); await Notifications.setNotificationChannelAsync('firebase-messaging-channel', { name: 'Firebase Notifications', description: 'Channel for Firebase Cloud Messaging', importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: '#FF231F7C', sound: 'default', }); console.log('Android notification channel setup complete for Firebase'); } catch (error) { console.error('Error creating Android notification channel:', error); } } } get fcmToken(): string | null { return this._fcmToken; } } // Set up background message handler FirebaseMessagingService.setBackgroundMessageHandler(async (remoteMessage) => { console.log('Message handled in the background!', remoteMessage); }); export default FirebaseMessagingService.getInstance();
Editor is loading...
Leave a Comment