无法在具有Web应用程序/PWA的FCM通知中使click_action起作用

7
我试图让我的“click_action”将用户带到我发送给客户的通知上的特定 URL,但无论我做什么(桌面端)都没有反应或只是打开了 PWA(Android)。消息通过得很好(在 Chrome 控制台中检查),但似乎点击不起作用。
以下是我在服务工作者中使用的代码,摘自各处,包括本网站提供的其他答案:
importScripts('https://www.gstatic.com/firebasejs/7.14.3/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.14.3/firebase-messaging.js');
// importScripts('/__/firebase/init.js');

/* An empty service worker!  */
self.addEventListener('fetch', function(event) {
  /* An empty fetch handler! */
});

   var firebaseConfig = {
//REDACTED
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);

 const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here


  notificationTitle = payload.notification.title;
  notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.icon,
    click_action: payload.notification.click_action
  };

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

self.addEventListener('notificationclick', function(event) {
    let url = event.notification.click_action;
// I've also added a data.click_action field in my JSON notification, and have tried using that
// instead, but that didn't work either

    console.log('On notification click: ', event.notification.tag); 
    event.notification.close(); // Android needs explicit close.
    event.waitUntil(
        clients.matchAll({ includeUncontrolled: true, type: 'window' }).then( windowClients => {
            // Check if there is already a window/tab open with the target URL
            for (var i = 0; i < windowClients.length; i++) {
                var client = windowClients[i];
                // If so, just focus it.
                if (client.url === url && 'focus' in client) {
                    return client.focus();
                }
            }
            // If not, then open the target URL in a new window/tab.
            if (clients.openWindow) {
                return clients.openWindow(url);
            }
        })
    );
});


self.onnotificationclick = function(event) {
  let url = event.notification.click_action;
  console.log('On notification click: ', event.notification.tag);
  event.notification.close();

  // This looks to see if the current is already open and
  // focuses if it is
  event.waitUntil(clients.matchAll({ includeUncontrolled: true, type: 'window' }).then(function(clientList) {
    for (var i = 0; i < clientList.length; i++) {
      var client = clientList[i];
      if (client.url == url && 'focus' in client)
        return client.focus();
    }
    if (clients.openWindow)
      return clients.openWindow(url);
  }));
};

在安卓设备(已安装PWA)和Chrome浏览器上,通知可以正常接收,并且开发者控制台中的消息载荷格式良好且接收正常。在从服务器发送的消息中,我有一个带有自定义参数的URL(例如,https://[domain]/list.php?userid=123),但是与上述情况相同,单击通知在Windows/Chrome上不起作用,在安卓设备上成功打开PWA,但随后不会转到载荷中的URL,而是转到了上次打开PWA时的位置。 "userid" 根据消息触发器而变化。

消息负载的JSON示例:

{data: {}, from: "xxx", priority: "high", notification: {}, collapse_key: "do_not_collapse"}
collapse_key: "do_not_collapse"
data: {gcm.notification.badge: "[logo URL]", click_action: "https://[URL]/list.php?userid=33"}
from: "xxx"
notification:
body: "'5' has just been added"
click_action: "https://[URL]/list.php?userid=33"
icon: "https://[logo URL]"
title: "alert "

我在https://firebase.google.com/docs/cloud-messaging/js/receive上看到了一些关于"webpush": {"fcm_options": {"link": "https://dummypage.com"}}的内容,但我无法确定它是否相关或是否也需要。

仅在click_action中提供URL点击通知时似乎并未执行该操作,这让我非常惊讶!在服务工作者中是否需要任何内容?!?!

问题之一可能是PWA不会定期更新SW,因此如果我上面的代码应该可以工作(大前提!),那么我只需要等待已安装的Android应用程序更新SW即可吗?如果是这样,有没有加快其更新速度的方法?

非常感谢您提前提供任何帮助。 这里让我非常困扰!

3个回答

6
这个问题和其他答案似乎与遗留的 FCM API 相关,而不是 v1。在这些情况下,我需要 SW 打开由 FCM 发送的任何 URL,但默认情况下不可能,因为主机不同(请看这里)。另外,通知对象已更改,并且 webpush 配置的 URL 现在在此处:event.notification.data.FCM_MSG.notification.click_action
因此,为了调整其他答案以获取正确的字段并仅通过编辑 firebase-messaging-sw.js 打开 URL:
importScripts('https://www.gstatic.com/firebasejs/8.2.10/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.2.10/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({
   ...
})

self.addEventListener('notificationclick', function(event) {
    event.notification.close();
    // fcp_options.link field from the FCM backend service goes there, but as the host differ, it not handled by Firebase JS Client sdk, so custom handling
    if (event.notification && event.notification.data && event.notification.data.FCM_MSG && event.notification.data.FCM_MSG.notification) {
        const url = event.notification.data.FCM_MSG.notification.click_action;
        event.waitUntil(
            self.clients.matchAll({type: 'window'}).then( windowClients => {
                // Check if there is already a window/tab open with the target URL
                for (var i = 0; i < windowClients.length; i++) {
                    var client = windowClients[i];
                    // If so, just focus it.
                    if (client.url === url && 'focus' in client) {
                        return client.focus();
                    }
                }
                // If not, then open the target URL in a new window/tab.
                if (self.clients.openWindow) {
                    console.log("open window")
                    return self.clients.openWindow(url);
                }
            })
        )
    }
}, false);

const messaging = firebase.messaging();


在初始化消息之前,注册addEventListener(事件监听器)。

你可以将以下代码: if (event.notification && event.notification.data && event.notification.data.FCM_MSG && event.notification.data.FCM_MSG.notification) 简化为: if (event.notification?.data?.FCM_MSG?.notification) 以减少代码长度。 - dustydojo
这在安卓的Firefox上似乎不起作用,只会打开about:blank,在安卓的Chrome上可以正常工作。 - jfaron

5

我花了很多时间寻找相同问题的解决方案。也许这可以帮助:

如果您使用Firebase Messaging发送通知,可以使用webpush字段。 Firebase Messaging客户端库执行self.registration.showNotification()...您的服务工作者中不再需要messaging.onBackgroundMessage

// firebabse-coud-function.js

app.messaging().send({
    webpush: {
        notification: {
            title: notification?.title || "Default title",
            icon: notification?.icon || "/icon.png",
            badge: notification?.icon || "/icon.png",
        },
        fcmOptions: {
            link: `${BASE_URL || ""}${notification?.clickAction || "/"}`,
        }
    },
    data: {
        userID: notification.userID,
        link: notification?.clickAction || "/",
    },
    topic
});

最重要的是,您需要在调用firebase.messaging()之前,在服务工作者中添加一个“notificationclick”事件监听器。

因此,我的服务工作者如下:

// firebase-messaging-sw.js

// ...

self.addEventListener('notificationclick', function (event) {
    console.debug('SW notification click event', event)
    const url = event.notification?.data?.FCM_MSG?.data?.link;
    // ...
})

const messaging = firebase.messaging();

messaging.onBackgroundMessage(function (payload) {
    // received others messages
})

对我来说,单击事件没有跳转到正确的网址。所以我添加了以下内容:

// background client - service worker
const channel = new BroadcastChannel('sw-messages');

self.addEventListener('notificationclick', function (event) {
  console.debug('SW notification click event', event)
  const url = event.notification?.data?.FCM_MSG?.data?.link;

  channel.postMessage({
    type: 'notification_clicked',
    data: {
      title: event.notification.title,
      clickAction: url
    }
  });

})

// foreground client
const channel = new BroadcastChannel('sw-messages');
channel.addEventListener("message", function (event) {
    // go the page
})

希望这能帮助到某些人。

const url = event.notification?.data?.FCM_MSG?.data?.link; 这正是我需要让我的工作起来的。谢谢。 - trainmania100
1
请问,这些问号的目的是什么?我以前从未见过。它是在评估之前检查键吗?这是原生JS还是一个包? - dev-jeff
@dev-jeff 请查看 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining 以及兼容性问题请参考 https://medium.com/@danwild.io/optional-chaining-for-javascript-with-babel-7-and-webpack-4-2de8fd9dbdd5 - anthony.perron

1
在调用firebase.messaging()之前,只需添加addeventlistner通知点击事件即可,一切都会正常工作。
importScripts('https://www.gstatic.com/firebasejs/8.4.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.4.1/firebase-messaging.js');


self.onnotificationclick = function(event) {
  console.log('On notification click: ', event.notification.tag);
  event.notification.close();

  // This looks to see if the current is already open and
  // focuses if it is
  event.waitUntil(clients.matchAll({
      type: "window"
  }).then(function(clientList) {
      for (var i = 0; i < clientList.length; i++) {
          var client = clientList[i];
          if (client.url == '/index' && 'focus' in client)
              return client.focus();
      }
      if (clients.openWindow)
          return clients.openWindow('/index');
  }));
};


var firebaseConfig = {
    apiKey: "xcxcxcxcxcxc",
    authDomain: "xcxcxc.firebaseapp.com",
    projectId: "fdsfdsdfdf",
    storageBucket: "dfsdfs",
    messagingSenderId: "sdfsdfsdf",
    appId: "sdfsdfsdfsdfsdfsdf"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);

  const messaging = firebase.messaging();


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接