【问题标题】:Firebase web Push notifications is triggered twice when using onBackgroundMessage()使用 onBackgroundMessage() 时会触发 Firebase 网络推送通知两次
【发布时间】:2021-06-16 05:20:01
【问题描述】:

我真的不知道这些事情是怎么回事。 我正在为我的网站正常使用 FCM 网络推送。如果我在前台,我可以在网站上收到消息,如果我在后台,我会收到通知。到目前为止一切顺利。

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

firebase.initializeApp({
  ...
});

const messaging = firebase.messaging();

问题在于 firebase-messaging-sw.js 的默认配置会在后台显示一个通知,显示 chrome 图标。我希望能够自定义此通知并显示我的应用程序图标。然后上网看了下发现需要用onBackgroundMessage()截取消息。

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

firebase.initializeApp({
  ...
});

const messaging = firebase.messaging();

if (messaging) {
  messaging.onBackgroundMessage(payload => {
    const notificationTitle = payload.notification.title || payload.data.title;
    const notificationOptions = {
      body: payload.notification.body || payload.data.subtitle || '',
      icon: 'https://firebasestorage.googleapis.com/v0/b/yes-4-web.appspot.com/o/pontonos%2Ficons%2Fandroid-chrome-192x192.png?alt=media&token=35616a6b-5e70-43a0-9284-d780793fa076',
      data: payload.data
    };

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

  self.addEventListener('notificationclick', event => {
    event.notification.close();
    event.waitUntil(clients.matchAll({ type: "window" }).then(function(clientList) {
      for (let i = 0; i < clientList.length; i++) {
        const client = clientList[i];
        if (client.url === '/' && 'focus' in client) {
          if (event.notification.data.route) client.href(event.notification.data.route);
          return client.focus();
        }
      }
      if (clients.openWindow)
        return clients.openWindow(event.notification.data.route || '/');
    }));
  });
}

问题是现在,当使用 onBackgroundMessage() 时,我会看到两个通知,一个是带有 chrome 图标的原始通知,另一个是带有我的应用程序图标的个性化消息(见图)

另一个问题是,如果我点击原始通知,带有我的网站的标签会成为主要焦点,但如果我点击个性化通知,则会打开一个带有我的网站的新标签。

【问题讨论】:

  • 你找到解决办法了吗?

标签: firebase push-notification firebase-cloud-messaging web-push


【解决方案1】:

可能为时已晚。

我遇到了这个问题,而我最终发现的问题是我在负载中发送了“通知”和“数据”对象。

删除“通知”并仅保留“数据”解决了问题。

来自 FCM 文档:

当您希望 FCM 代表您的客户端应用处理显示通知时,请使用通知消息。当您想在客户端应用程序上处理消息时,请使用数据消息。

FCM 可以发送包含可选数据负载的通知消息。在这种情况下,FCM 处理通知负载的显示,客户端应用处理数据负载。

这是我的有效载荷现在的样子:

$payload = [
            'message' => [
                'token' => $token,
                'data'  => $msg,
                //'notification'  => $msg, (this caused the notification to deliver twice)
                'webpush'=> [
                  'fcm_options'=> [
                    'link' => $link,
                    'analytics_label' => 'notification_label'
                  ]
                ]
            ],
        ];

https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

【讨论】:

  • 编辑了我的原始答案以显示我的工作场景@tmath的有效负载
【解决方案2】:

如果您有自定义通知,请不要在 POST 有效负载上使用 notification。改为data 或其他关键字。

{ 
   "to": "fH7CtR77FgxZsGiwbBwNT5:APA91bGSOeIW7o34lppBErHuCiapYOs5xrj1WOw1IR6gvn2TW3HsEGdyV5yfcyYksauhKCKXTWnbaULukPyJrH34Ht0GsonBt6_gYH9UdN_S3wR6w0ZDLSDo7iPbYO6Wbcyvw_9RTvi3",
    "priority": "high",
    "data": {
        "title": "Title",
        "body" : "First Notification",
        "text": "Text"
    }
}
function onBackgroundMessage() {
  const messaging = firebase.messaging();

  // [START messaging_on_background_message]
  messaging.onBackgroundMessage((payload) => {
    console.log('[firebase-messaging-sw.js] Received background message ', payload);
    const notification = payload.data;   -----> here is custom
    if (!notification) {
      console.warn('[firebase-messaging-sw.js] Unknown notification on message ', payload);
      return
    }

    // Customize notification here
    const notificationOptions = {
      ...notification,
      icon: '/img/icons/favicon-32x32.png'
    };

    self.registration.showNotification(
      notification.title,
      notificationOptions);
  });
}

onBackgroundMessage();

【讨论】:

    【解决方案3】:

    两次通知时我遇到了同样的问题。我不想使用 Firebase 控制台来测试您的通知。改用邮递员/失眠症。 您的通知被触发了两次,因为在 Firebase 控制台中,它们发送数据通知并且仅发送通知。这是我的 JSON 数据:

    {
        "to": "epasJ3fYJG3pjXC8UHCg37:APA91bHEbtPBtRzgEOKGR9Kg9DkZbHLdnMT2uEseQ8AzCSPKv8PkLsm_dkfN_AagFRcVhmOOqBlF9mNXtl7KqelG2g9tbeKTH1_Ey9KAGaNRGKwrIyttH58dP-jAWiGYKxLHu3mgdUMN",
    
        /* here the problem. If you use both of them, you'll get notification twice. Just pick one. Notification key or data key */
    
        "notification": {
            "title": "Test title send from insomnia",
            "body": "Test body send from insomnia",
            "image": "https://mostrans.co.id/CompanyProfile/static/media/logo-mostrans.ff215158.png"
        },
        "data": {
            "title": "Test title send from insomnia",
            "body": "Test body send from insomnia",
            "image": "https://mostrans.co.id/CompanyProfile/static/media/logo-mostrans.ff215158.png"
        }
    }
    

    点击您的自定义通知,您可以这样做

    const urlToOpen = new URL("/", self.location.origin).href;
    
      const promiseChain = clients
        .matchAll({
          type: "window",
          includeUncontrolled: true,
        })
        .then((windowClients) => {
          let matchingClient = null;
    
          for (let i = 0; i < windowClients.length; i++) {
            const windowClient = windowClients[i];
            if (windowClient.url === urlToOpen) {
              matchingClient = windowClient;
              break;
            }
          }
    
          if (matchingClient) {
            return matchingClient.focus();
          } else {
            return clients.openWindow(urlToOpen);
          }
        });
    
      event.waitUntil(promiseChain);

    阅读更多here

    【讨论】:

      【解决方案4】:

      如果您使用 Firebase Admin 发送消息,您可以 console.log in onBackgroundMessage FCM 将发送一些数据,如下所示。

      有效载荷包括属性notification,来自FCM Documentation

      使用 FCM,您可以向客户端发送两种类型的消息:

      通知消息,有时被认为是“显示消息”。 这些由 FCM SDK 自动处理。

      这意味着,如果您的数据具有属性notification,它将由 FCM 自动处理,您无需在 onBackgroundMessage 中添加显示通知的方法强>.

      如果在onBackgroundMessage中添加显示通知的方法,预计会显示两次,因为第一个notif由FCM自动处理,第二个由@处理987654329@.

      如果您不希望 FCM 自动显示通知,您只需从负载中删除属性 notification

      你可以试试这个:

      //Insert to firebase-messaging-sw.js
      
      firebase.initializeApp(firebaseConfig);
      
      
      class CustomPushEvent extends Event {
        constructor(data) {
          super('push');
      
          Object.assign(this, data);
          this.custom = true;
        }
      }
      
      /*
       * Overrides push notification data, to avoid having 'notification' key and firebase blocking
       * the message handler from being called
       */
      self.addEventListener('push', (e) => {
        // Skip if event is our own custom event
        if (e.custom) return;
      
        // Kep old event data to override
        const oldData = e.data;
      
        // Create a new event to dispatch, pull values from notification key and put it in data key,
        // and then remove notification key
        const newEvent = new CustomPushEvent({
          data: {
            ehheh: oldData.json(),
            json() {
              const newData = oldData.json();
              newData.data = {
                ...newData.data,
                ...newData.notification,
              };
              delete newData.notification;
              return newData;
            },
          },
          waitUntil: e.waitUntil.bind(e),
        });
      
        // Stop event propagation
        e.stopImmediatePropagation();
      
        // Dispatch the new wrapped event
        dispatchEvent(newEvent);
      });

      Source Code Github

      上面的代码将属性notification中的key移动到data,所以预期的结果如下

      这样,FCM 将不会显示通知,因为有效负载没有属性 notification

      【讨论】:

        【解决方案5】:

        这是预期的行为。

        github issue

        【讨论】:

          【解决方案6】:

          您可以隐藏通知,评论显示通知

           messaging.onBackgroundMessage((payload) => {
              console.log('[firebase-messaging-sw.js] Received background message ', payload);
              // Customize notification here
              const notificationTitle = payload.notification.title||'';
              const notificationOptions = {
                body: payload.notification.body||'',
                icon: '/firebase-logo.png'
              };
            
              // self.registration.showNotification(notificationTitle,
              //   notificationOptions);
                self.registration.hideNotification();
            });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-06-11
            • 2018-02-26
            • 1970-01-01
            • 1970-01-01
            • 2023-01-31
            • 2017-04-16
            相关资源
            最近更新 更多