You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中实现Firebase实时通知?跨端推送新消息至全用户

Hey there! Let's walk through exactly how to build WhatsApp-style cross-platform notifications (Android, iOS, Web) using Firebase Realtime Database paired with Firebase Cloud Messaging (FCM). I've implemented this setup for a few chat apps, so I'll share the practical steps and code snippets you need.

1. Prerequisites: Set Up Firebase Services First

First, make sure each of your platforms is properly integrated with both Firebase Realtime Database and FCM:

  • Android: Add the google-services.json file, include FCM dependencies in your build.gradle, and enable internet permissions.
  • iOS: Add GoogleService-Info.plist, configure APNs certificates in Firebase Console, and enable push notifications in your Xcode project.
  • Web: Initialize Firebase in your web app, include the FCM SDK, and set up a service worker for background notifications.
2. Core Logic: Trigger Notifications via Cloud Functions

You shouldn't send FCM notifications directly from client apps (it's insecure and can be abused). Instead, use Cloud Functions for Firebase to listen for new messages in Realtime Database and trigger FCM pushes automatically.

Step 2.1: Write the Cloud Function

Here's a sample TypeScript function that listens for new messages in a messages/{chatId}/{messageId} path, fetches the recipient's FCM token, and sends a notification:

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();

export const sendMessageNotification = functions.database
  .ref("/messages/{chatId}/{messageId}")
  .onCreate(async (snapshot, context) => {
    const messageData = snapshot.val();
    const { senderId, recipientId, text, chatId } = messageData;

    // Fetch recipient's FCM token from your users collection
    const recipientSnapshot = await admin.database().ref(`/users/${recipientId}/fcmToken`).once("value");
    const recipientToken = recipientSnapshot.val();

    if (!recipientToken) {
      functions.logger.log("No FCM token found for recipient");
      return null;
    }

    // Fetch sender's info to show in notification
    const senderSnapshot = await admin.database().ref(`/users/${senderId}`).once("value");
    const senderInfo = senderSnapshot.val();

    // Build FCM notification payload
    const payload = {
      notification: {
        title: senderInfo.name,
        body: text,
        sound: "default",
        click_action: "OPEN_CHAT_ACTIVITY" // Android-specific: defines what happens on click
      },
      data: {
        chatId: chatId,
        senderId: senderId,
        messageText: text
      },
      token: recipientToken
    };

    // Send the notification
    return admin.messaging().send(payload);
  });

Deploy this function using firebase deploy --only functions.

3. Platform-Specific Notification Handling

Now, let's configure each platform to receive and display the notification like WhatsApp.

3.1 Android Implementation

Step 3.1.1: Create a Notification Channel (Android 8.0+)

In your Application class or MainActivity, create a channel for chat notifications:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "CHAT_NOTIFICATIONS",
        "Chat Messages",
        NotificationManager.IMPORTANCE_HIGH
    ).apply {
        description = "Notifications for incoming chat messages"
        enableVibration(true)
        vibrationPattern = longArrayOf(0, 500, 200, 500)
    }
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.createNotificationChannel(channel)
}

Step 3.1.2: Handle FCM Messages with FirebaseMessagingService

Create a subclass to process incoming notifications:

class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        
        // Check if user is already in the chat activity for this chatId
        // (You'll need to track active chat state in your app)
        val isChatActive = MyAppState.isChatActive(remoteMessage.data["chatId"])
        if (isChatActive) return // Don't show notification if user is already in the chat

        // Build WhatsApp-style notification
        val intent = Intent(this, ChatActivity::class.java).apply {
            putExtra("chatId", remoteMessage.data["chatId"])
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            intent,
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )

        val notificationBuilder = NotificationCompat.Builder(this, "CHAT_NOTIFICATIONS")
            .setSmallIcon(R.drawable.ic_notification)
            .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.sender_avatar)) // Replace with sender's avatar
            .setContentTitle(remoteMessage.notification?.title)
            .setContentText(remoteMessage.notification?.body)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .setGroup("CHAT_GROUP_${remoteMessage.data["chatId"]}") // Group notifications by chat

        val notificationManager = NotificationManagerCompat.from(this)
        notificationManager.notify(remoteMessage.data["chatId"]?.hashCode() ?: 0, notificationBuilder.build())
    }

    override fun onNewToken(token: String) {
        super.onNewToken(token)
        // Save this token to your Realtime Database under the user's profile
        FirebaseDatabase.getInstance().ref("/users/${currentUserId}/fcmToken").setValue(token)
    }
}

Don't forget to register this service in your AndroidManifest.xml:

<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

3.2 iOS Implementation

Step 3.2.1: Request Push Permissions

In your AppDelegate (or SceneDelegate for iOS 13+), request push permissions on app launch:

import FirebaseMessaging

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    
    // Request push permissions
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
        guard granted else { return }
        DispatchQueue.main.async {
            application.registerForRemoteNotifications()
        }
    }
    
    Messaging.messaging().delegate = self
    return true
}

Step 3.2.2: Handle FCM Messages

Implement MessagingDelegate and handle incoming notifications:

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        guard let token = fcmToken else { return }
        // Save token to Realtime Database
        Database.database().reference().child("users/\(currentUserId)/fcmToken").setValue(token)
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // Check if user is in the chat screen for this message
        let userInfo = notification.request.content.userInfo
        let chatId = userInfo["chatId"] as? String
        if ChatManager.shared.isActiveChat(chatId) {
            completionHandler([]) // Don't show notification
        } else {
            completionHandler([.banner, .sound, .badge])
        }
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        let chatId = userInfo["chatId"] as? String
        
        // Open chat screen
        if let window = UIApplication.shared.windows.first {
            let chatVC = ChatViewController()
            chatVC.chatId = chatId
            window.rootViewController = UINavigationController(rootViewController: chatVC)
            window.makeKeyAndVisible()
        }
        completionHandler()
    }
}

3.3 Web Implementation

Step 3.3.1: Register Service Worker

Create a firebase-messaging-sw.js file in your web root:

importScripts("https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging-compat.js");

firebase.initializeApp({
    apiKey: "YOUR_API_KEY",
    authDomain: "YOUR_AUTH_DOMAIN",
    projectId: "YOUR_PROJECT_ID",
    storageBucket: "YOUR_STORAGE_BUCKET",
    messagingSenderId: "YOUR_SENDER_ID",
    appId: "YOUR_APP_ID"
});

const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
    const notificationTitle = payload.notification.title;
    const notificationOptions = {
        body: payload.notification.body,
        icon: "/icons/notification-icon.png",
        data: payload.data
    };

    self.registration.showNotification(notificationTitle, notificationOptions);
});

// Handle notification click
self.addEventListener('notificationclick', (event) => {
    event.notification.close();
    // Open chat page with chatId from data
    const chatId = event.notification.data.chatId;
    event.waitUntil(
        clients.openWindow(`/chat/${chatId}`)
    );
});

Step 3.3.2: Initialize FCM in Your Web App

In your main JS file:

import { initializeApp } from "firebase/app";
import { getMessaging, getToken, onMessage } from "firebase/messaging";

const firebaseConfig = {
    // Your Firebase config details
};

const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);

// Request notification permission
Notification.requestPermission().then((permission) => {
    if (permission === "granted") {
        getToken(messaging, { vapidKey: "YOUR_VAPID_KEY" }).then((currentToken) => {
            if (currentToken) {
                // Save token to Realtime Database via your backend endpoint
                fetch(`/api/save-fcm-token?token=${currentToken}`, { method: "POST" });
            }
        });
    }
});

// Handle foreground messages
onMessage(messaging, (payload) => {
    const chatId = payload.data.chatId;
    // Check if user is already in the chat tab
    if (window.location.pathname === `/chat/${chatId}`) return;
    
    // Show in-app notification (like WhatsApp's web toast)
    showInAppNotification(payload.notification.title, payload.notification.body);
});
4. Key Enhancements for WhatsApp-Like Behavior
  • Notification Grouping: Group notifications by chat (as shown in Android code with setGroup) so users can expand/collapse chat threads.
  • Online Status Check: Track if a user is active in the chat to avoid sending unnecessary notifications (we added checks in each platform's code).
  • Rich Notifications: Add sender avatars, long text previews, and action buttons (like "Reply" directly from the notification).
  • Silent Notifications: For background sync, use FCM data messages instead of notification messages to update the app without showing a toast.

内容的提问来源于stack exchange,提问作者waleed ragab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:45:33