即使在发送消息后,也不会在 React 应用程序中触发 Firebase 云消息传递 onMessage

Posted

技术标签:

【中文标题】即使在发送消息后,也不会在 React 应用程序中触发 Firebase 云消息传递 onMessage【英文标题】:Firebase cloud messaging onMessage not triggered in React app even after message is sent 【发布时间】:2019-08-28 18:03:30 【问题描述】:

我正在我的 React 应用程序中测试 Firebase 云消息传递功能,该应用程序由 create-react-app 引导。请注意,我已经正确初始化了 firebase(包括服务器端的管理 SDK),并且我的客户端部署在 https 上。到目前为止,我所做的是:

    在 firebase.js 中初始化 firebase 消息,同时请求通知权限并监听 onMessage 事件
const messaging = firebase.messaging();
messaging
  .requestPermission()
  .then(() => 
    console.log("Permission granted!");
  )
  .catch(() => 
    console.log("Permission denied!");
  );

messaging.onMessage(payload => 
  console.log("onMessage: ", payload);
);
    在公共目录中创建 service worker 文件 firebase-messaging-sw.js
importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js");

var config = 
  messagingSenderId: <messageID hidden>
;
firebase.initializeApp(config);

const messaging = firebase.messaging();

    我从另一个 *** 帖子中读到,在 create-react-app 帖子中,这也必须包含在 index.js 中
if ("serviceWorker" in navigator) 
  navigator.serviceWorker
    .register("../firebase-messaging-sw.js")
    .then(function(registration) 
      console.log("Registration successful, scope is:", registration.scope);
    )
    .catch(function(err) 
      console.log("Service worker registration failed, error:", err);
    );

    为了轻松测试消息传递,我在 Main.js 中添加了一个按钮,该按钮将在单击时将令牌发送到我的服务器(然后服务器将继续发送消息)
const handlePushButtonClick = () => 
    messaging.getToken().then(token => 
      axios.post(<Server link hidden>, 
        token
      );
    );
  ;
    然后我像这样在我的快速服务器中设置必要的路由
app.post("/api/push", async (req, res) => 
    const registrationToken = req.body.token;
    var message = 
      data: 
        score: "850",
        time: "2:45"
      ,
      token: registrationToken
    ;
    fb.admin
      .messaging()
      .send(message)
      .then(response => 
        console.log("Successfully sent message:", response);
        res.sendStatus(200);
      )
      .catch(error => 
        console.log("Error sending message:", error);
      );
  );

这是问题所在,我已验证我的服务器已成功接收令牌并且实际上已成功发送消息,但在我的客户端,我根本没有收到 onMessage 有效负载对象。

从我的代码中回想一下,我希望在客户端开发控制台上收到的是带有 onMessage 和有效负载的 console.log。

messaging.onMessage(payload => 
  console.log("onMessage: ", payload);
);

【问题讨论】:

【参考方案1】:

解决此问题的简单方法是将您的 Firebse 更新到 最新版本。

例如。

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

注意:一旦您更新了您的 firebase 库版本,那么 messagingSenderId 将无法在您的 firebase-messaging-sw.js 文件中使用。您必须提供所有其他参数,例如。 apiKeyprojectIdappId 以及 messagingSenderId

例如。

在你的 firebase-messaging-sw.js

中替换它
firebase.initializeApp(
    messagingSenderId: "Sender ID"
);

有了这个

firebase.initializeApp(
        apiKey: "api-key",
        authDomain: "project-id.firebaseapp.com",
        databaseURL: "https://project-id.firebaseio.com",
        projectId: "project-id",
        storageBucket: "project-id.appspot.com",
        messagingSenderId: "sender-id",
        appId: "app-id",
);
如果还是不行。清理浏览器缓存并重新注册 Service Worker。

【讨论】:

但是来自服务工作者的后台通知确实可以单独使用messagingSenderId。 @andreszs 如果您将 Firebase sdk 更新为最新版本(firebasejs/7.8.0/firebase-app.js' & firebasejs/7.8.0/firebase-messaging.js)。它会告诉你错误。 SW 中缺少某种项目 ID。要解决这个问题,您需要添加其余的详细信息。并且经过测试。 要触发 onMessage 事件,您必须更新您的 Firebase SDK。 9.6.1 上同样的问题【参考方案2】:

我发现了我的错误。我最初遵循本指南:https://firebase.google.com/docs/cloud-messaging/js/topic-messaging。当我按照教程进行操作时,我之前的错误对我来说不是很清楚,但这可能是因为我对通知和推送 Web API 非常不熟悉。

教程的消息对象里面有一个数据对象:

var message = 
  data: 
    score: '850',
    time: '2:45'
  ,
  token: registrationToken
;

事实证明,如果我想在消息中发送数据负载,我需要在我的 firebase-messaging-sw.js 中包含这组代码(我链接的教程中没有显示这一点):

messaging.setBackgroundMessageHandler(payload => 
  const title = payload.data.title;
  const options = 
    body: payload.data.score
  ;
  return self.registration.showNotification(title, options);
);

请注意,仅当您要发送数据有效负载(此后您可以在 service worker 文件中灵活操作)时,才需要 service worker 文件中的上述代码。如果你只需要发送一个通知,你的消息对象应该简单地包含一个通知对象(它只能接受一些固定的键):

var message = 
  notification: 
    title: '850',
    body: '2:45'
  ,
  token: registrationToken
;

【讨论】:

前台和后台应该有相同的有效载荷。您为通知建议了两种不同的解决方案。根据您的逻辑,如果要发送前台消息需要使用通知有效负载。而对于后台消息需要使用数据有效载荷。但这种解决方案并不理想。使用上述解决方案,您将仅通过数据有效负载来实现两者。

以上是关于即使在发送消息后,也不会在 React 应用程序中触发 Firebase 云消息传递 onMessage的主要内容,如果未能解决你的问题,请参考以下文章

即使 DB 已正确更新,React UI 也不会在单击时重新呈现。第二次点击后,UI 重新渲染

即使在调用 setState 之后,React.js 子状态也不会重新渲染?

即使使用代理,Nodejs 也不会为 React CRA 应用程序设置 cookie

在 SockJsClient (React) 中握手后无法发送消息

发送 15 条消息后,带有套接字的 React 聊天应用程序变慢

使用 React 和 Socket.io 的聊天应用程序在发送太多消息后挂起