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

如何隐藏Firebase FCM Service Worker密钥并解决onMessage失效问题

Firebase FCM 隐藏Service Worker密钥并恢复onMessage触发的解决方案

核心问题说明

  1. Service Worker属于静态资源,无法直接读取前端框架(如Next.js)的环境变量,硬编码密钥存在安全风险。
  2. 删除Service Worker中的Firebase配置后,FCM的messaging实例未初始化,推送事件处理链路断裂,导致页面中onMessage函数无法正常触发。

解决方案步骤

1. 页面端传递Firebase配置

页面可正常读取环境变量,初始化FCM后,将配置发送给已激活的Service Worker。

2. Service Worker动态初始化

让Service Worker监听页面发送的配置消息,完成Firebase初始化,确保推送事件处理逻辑正常运行。

修改后的代码示例

/src/components/Message.tsx

import React, { useEffect, useState } from 'react';
import { messageState } from '@/libs/recoilState';
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';
import { useRecoilState } from 'recoil';

export interface MessageType {
  title: string;
  reservationId: string;
  description: string;
  [key: string]: string;
}

const Message = () => {
  const [message, setMessage] = useRecoilState<MessageType>(messageState);
  const onMessageFCM = async () => {
    const permission = await Notification.requestPermission();
    if (permission !== 'granted') return;

    // 读取环境变量中的Firebase配置
    const firebaseConfig = {
      apiKey: process.env.NEXT_PUBLIC_API_KEY,
      authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN,
      projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
      storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET,
      messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_ID,
      appId: process.env.NEXT_PUBLIC_APP_ID,
      measurementId: process.env.NEXT_PUBLIC_MEASUREMENT_ID,
    };

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

    // 向Service Worker发送配置
    if ('serviceWorker' in navigator) {
      const registration = await navigator.serviceWorker.ready;
      registration.active?.postMessage({
        type: 'SET_FIREBASE_CONFIG',
        config: firebaseConfig
      });
    }

    getToken(messaging, {
      vapidKey: process.env.NEXT_PUBLIC_VAPID_KEY,
    })
      .then((currentToken) => {
        if (currentToken) {
          console.log(currentToken);
        } else {
          console.log('No registration token available. Request permission to generate one.');
        }
      })
      .catch((err) => {
        console.log('An error occurred while retrieving token. ', err);
      });

    onMessage(messaging, (payload) => {
      console.log('Message received. ', payload);
      setMessage(payload?.data as MessageType); 
    });
  };

  useEffect(() => {
    onMessageFCM();
  }, []);

  return <>></>;
};

export default Message;

public/firebase-messaging-sw.js

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

let messaging = null;

// 监听页面发送的配置消息
self.addEventListener('message', (event) => {
  if (event.data?.type === 'SET_FIREBASE_CONFIG' && !messaging) {
    firebase.initializeApp(event.data.config);
    messaging = firebase.messaging();
    console.log('Firebase initialized in Service Worker');
  }
});

self.addEventListener('push', function(event) {
  console.log("处理收到的推送数据并显示为通知的内容")
  // 可选:自定义通知展示逻辑
  if (event.data) {
    const payload = event.data.json();
    event.waitUntil(
      self.registration.showNotification(payload.notification.title, {
        body: payload.notification.body,
        icon: '/firebase-logo.png'
      })
    );
  }
});

self.addEventListener('notificationclick', function(event) {
  console.log("点击弹出的通知窗口时要处理的内容")
  event.notification.close();
  // 可选:打开指定页面
  event.waitUntil(
    clients.openWindow('/')
  );
});

关键注意事项

  • 环境变量必须以NEXT_PUBLIC_为前缀,Next.js仅会将此类变量暴露给客户端代码。
  • 代码中通过navigator.serviceWorker.ready确保Service Worker激活后再发送配置,避免初始化失败。
  • 若Service Worker已提前激活,可能需要刷新页面让配置生效,也可在sw中添加本地存储逻辑缓存配置,减少重复发送。

内容的提问来源于stack exchange,提问作者Yeongjun Kim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:43:21