使用 onBackgroundMessage() 时,Firebase Web 推送通知会触发两次

问题描述 投票:0回答:7

我真的不知道这些事情是怎么回事。 我的网站通常使用 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
7个回答
22
投票

可能为时已晚。

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

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

来自 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


12
投票

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

有效负载包括属性

notification
,来自 FCM 文档

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

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

这意味着,如果您的数据具有属性

notification
,它将由FCM自动处理,您不需要在onBackgroundMessage中添加显示通知的方法。

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

onBackgroundMessage
处理。

如果您不希望 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);
});

源代码Github

上面的代码会将属性

notification
中的键移动到
data
,所以预期的结果如下

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

notification


4
投票

如果您有自定义通知,请勿在 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();


2
投票

我也遇到了同样的问题,两次通知。我不想使用 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);

阅读更多这里


1
投票

这是预期的行为。

github问题


0
投票

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

 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();
  });

0
投票
const backgroundMessaging = firebase.messaging();

backgroundMessaging.onBackgroundMessage(function(payload) {
  console.log('Received background message ', payload);

  // Customize notification here
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
  };

  // hide the registration notification 
  // self.registration.showNotification(notificationTitle, notificationOptions);

});
© www.soinside.com 2019 - 2024. All rights reserved.