【问题标题】:FCM Push notifications arrive twice if the browser is in background如果浏览器在后台,FCM 推送通知会到达两次
【发布时间】:2017-10-11 13:57:55
【问题描述】:

我已经建立了一个简单的推送通知站点,如果浏览器在前台,通知就可以到达。

如果浏览器在后台,问题就开始了:通知到达两次,一次设置了图像样式和其他设置,另一次只有标题和正文消息。

Service Worker 的内容:

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

// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
    'messagingSenderId': '...'
});

const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
    console.log('[firebase-messaging-sw.js] Received background message ', 
    return null;
});

self.addEventListener('install', function (event) {
    event.waitUntil(skipWaiting());
});

self.addEventListener('activate', function (event) {
    event.waitUntil(clients.claim());
});

self.addEventListener('push', function (event) {
    var pushData = event.data.json();
    try {
        var notificationData = pushData.data;
        notificationData.data = JSON.parse(notificationData.data);
        console.log(notificationData);
        self.registration.showNotification(pushData.notification.title, notificationData);
    }
    catch (err) {
        console.log('Push error happened: ', err);
    }
});

客户端js:

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

messaging.onMessage(function (payload) {
    console.log("notification recieved");
    return null;
});

self.addEventListener('push', function (event) {
    console.log("window push stuff");
    return null;
});

谢谢!

【问题讨论】:

    标签: javascript google-chrome firebase-cloud-messaging


    【解决方案1】:

    100% 避免多个通知的最简单方法是添加“标签”,例如:

    var options = {
        body: "text",
        tag: "notification-1"
    };
    self.registration.showNotification("title", options)
    

    【讨论】:

    • @judasane 唯一标识消息,所以它只弹出一次,而不是多次。
    【解决方案2】:

    这个问题可以通过在messaging.setBackgroundMessageHandler事件中加入这一行来解决:

    self.registration.hideNotification();
    

    这样,默认通知将不会显示,您必须在 self.addEventListener 事件中显示您的通知。

    【讨论】:

    【解决方案3】:

    这就是我如何让 Firebase 云消息传递通知在具有这些要求的 Android 设备上的 Progresse Web 应用程序中工作:

    1. 推送通知也应该只在状态栏中出现一次
    2. 通知数量应在 PWA 应用图标上突出显示
    3. 状态栏中的通知应包含:
    • 带有应用图标的小徽章
    • 实际应用图标
    • 通知标题
    • 通知正文
    • 点击打开 PWA

    firebase-messaging.sw.js

    不要向该文件添加任何 cdoe 或 onBackgroundMessage() 处理程序。我的文件不过是

    //Give the service worker access to Firebase Messaging.
    // Note that you can only use Firebase Messaging here. Other Firebase libraries
    // are not available in the service worker.
    importScripts('https://www.gstatic.com/firebasejs/8.3.0/firebase-app.js');
    importScripts('https://www.gstatic.com/firebasejs/8.3.0/firebase-messaging.js');
    
    // Initialize the Firebase app in the service worker by passing in
    // your app's Firebase config object.
    // https://firebase.google.com/docs/web/setup#config-object
    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',
      measurementId: 'G-measurement-id',
    });
    
    // Retrieve an instance of Firebase Messaging so that it can handle background
    // messages.
    if (firebase.messaging.isSupported()) {
      const messaging = !firebase.apps.length
        ? firebase.initializeApp(firebaseConfig).messaging()
        : firebase.app().messaging();
    

    发送通知的服务器端作业

    消息负载的内容和结构是关键。将您的通知对象放入 webpush 对象中。请勿添加数据对象,以免出现内容不完整的重复通知。

    确保您的徽章是 24x24px png,仅包含透明背景上的白色内容。

      var message = {
        webpush: {
          notification: {
            title: "Let's Join App",                          // Your message title
            body: messageBody,                                // Your message body
            icon: "./img/icons/android-chrome-192x192.png",   // Your App icon, up to 512x512px, any color
            badge: "./img/icons/badge.png",                   // Your app badge, 24x24px, white content on transparent background
          },
          fcmOptions: {
            link: "https://www.letsjoin.app",                 // Your Link
          },
        },
        token,
      };
    
      // Send a message to the device corresponding to the provided
      // registration token.
      await admin
        .messaging()
        .send(message)
        .then((response) => {
          // Response is a message ID string.
          console.log("Successfully sent message");
        })
        .catch((error) => {
          console.log("Error sending message:", error.errorInfo.message);
        });
    };
    

    【讨论】:

    • 在向主题发送通知时是否同样有效?
    【解决方案4】:

    我花了大约两周的时间来理解和解决这个问题。希望这会为其他人节省时间:

    Firebase 支持两种类型的推送通知:

    1. 显示 FCM SDK 自动处理的通知数据
    2. 数据消息,由客户端应用处理

    Firebase 云消息传递 UI 具有许多优势,例如按国家、设备、语言等进行高级定位。但它只允许在数据自定义字段内发送 URL。

    从 Firebase 控制台 UI 发送的消息如下所示:

     {
        notification: {
          title: "New Test",
          body: "This is test",
        },
        data: {
          url: 'someurl.com',
        },
      };
    

    Service Worker 处理通知时会发出两次通知,FCM SDK 自动处理时会发出第二次通知。

    我没有找到在前端禁用通知自动处理的方法,并使用 Firebase 函数将其仅作为数据消息发送:

     {
        data: {
          title: "New Test",
          body: "This is test",
          url: 'someurl.com',
        },
      };
    

    因此,如果您想将自定义 URL 传递给推送通知,则需要从您自己的服务器或使用 firebase 函数发送。

    【讨论】:

      猜你喜欢
      • 2019-08-01
      • 2018-01-24
      • 2022-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多