服务工作者“notificationclick”未触发

Posted

技术标签:

【中文标题】服务工作者“notificationclick”未触发【英文标题】:Service Worker "notificationclick" not firing 【发布时间】:2020-11-11 21:06:41 【问题描述】:

通知显示正常,但是当我单击它或执行任何操作时,什么都没有发生。我没有看到任何日志记录,也没有错误消息,但通知确实关闭了(尽管即使我注释掉 event.notification.close() 它也会关闭)。

我尝试使用 Chrome 调试器,并且可以在显示通知的代码中设置断点,但 notificationclick 处理程序中的所有断点都无法暂停执行。

我花了几天的时间试图让它工作,但我束手无策。

const auth = firebase.auth();
const functions = firebase.functions();
const done = functions.httpsCallable("done");
const snooze = functions.httpsCallable("snooze");

self.addEventListener("notificationclick", event => 
  console.log("notificationclick", event);
  const uid = auth.currentUser.uid;
  const  id, url  = event.notification.data;

  event.notification.close();
  event.waitUntil(() => 
    switch (event.action) 
      case "done":
        console.log("Done");
        return done( uid, id );
      case "snooze1":
        console.log("Snooze 1 Hour");
        return snooze( uid, id, hours: 1 );
      case "snooze24":
        console.log("Snooze 1 Day");
        return snooze( uid, id, hours: 24 );
      default:
        console.log("Open App");
        return clients
          .matchAll(
            includeUncontrolled: true,
            type: "window"
          )
          .then(clientList => 
            for (let i = 0; i < clientList.length; i++) 
              let client = clientList[i];
              if (url[0] === "#") 
                if (client.url.endsWith(url) && "focus" in client) 
                  return client.focus();
                
               else 
                if (
                  client.url.replace(/#.*$/, "") === url &&
                  "focus" in client
                ) 
                  return client.focus();
                
              
            
            if (clients.openWindow) 
              return clients.openWindow(location.origin + url);
            
          );
    
  );
);

firebase
  .messaging()
  .setBackgroundMessageHandler(( data:  title, options  ) => 
    options = JSON.parse(options);
    options.actions = [
       action: "done", title: "Done" ,
       action: "snooze1", title: "Snooze 1 Hour" ,
       action: "snooze24", title: "Snooze 1 Day" 
    ];

    return self.registration.showNotification(title, options);
  );

【问题讨论】:

【参考方案1】:

你好,你可以试试下面的代码,看看它是否被调用-

 self.addEventListener('notificationclick', function (event) 
        event.notification.close();
        var redirectUrl = null;
        var tag = event.notification.tag;
        if (event.action) 
            redirectUrl = event.action
         
        if (redirectUrl) 
            event.waitUntil(async function () 
                var allClients = await clients.matchAll(
                    includeUncontrolled: !0
                );
                var chatClient;
                for (const client of allClients) 
                    if (redirectUrl != '/' && client.url.indexOf(redirectUrl) >= 0) 
                        client.focus();
                        chatClient = client;
                        break
                    
                
                if (chatClient == null || chatClient == 'undefined') 
                    chatClient = clients.openWindow(redirectUrl);
                    return chatClient
                
            ().then(result => 
                if (tag) 
                    //PostAction(tag, "click")
                
            ))
        
    );

编辑- 附加两个js文件。它在我的最后工作。

firebase-messaging-sw.js

importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-messaging.js');
var config = 
    apiKey: "your api key",
    authDomain: "you firebase domain",
    databaseURL: "your firbase db url",
    projectId: "your project id",
    storageBucket: "",
    messagingSenderId: "sender id"
;

firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) 
    console.log('[firebase-messaging-sw.js] Received background message ', payload.data);    
    var notificationTitle = payload.data.Title;
    var notificationOptions = 
        body: payload.data.Body,
        icon: payload.data.Icon,
        image: payload.data.Image,
        action: payload.data.ClickAction
    ;
    console.log("strated sending msg" + notificationOptions);
    return self.registration.showNotification(notificationTitle,notificationOptions);
);

self.addEventListener('notificationclick', function (event) 
    console.log('On notification click: ', event.notification);
    event.notification.close();
    var redirectUrl = null;
    if (event.notification.data) 
        if (event.notification.data.FCM_MSG) 
            redirectUrl = event.notification.data.FCM_MSG.data ? event.notification.data.FCM_MSG.data.click_action : null
         else   
            redirectUrl = event.notification.data ? event.notification.data.click_action : null
        
    
    console.log("redirect url is : " + redirectUrl);

    if (redirectUrl)        
        event.waitUntil(async function () 
            var allClients = await clients.matchAll(
                includeUncontrolled: true
            );
            var chatClient;            
            for (var i = 0; i < allClients.length; i++) 
                var client = allClients[i];                
                if (client['url'].indexOf(redirectUrl) >= 0) 
                    client.focus();
                    chatClient = client;
                    break;
                
            
            if (chatClient == null || chatClient == 'undefined') 
                chatClient = clients.openWindow(redirectUrl);
                return chatClient;
            
        ());        
    
);

self.addEventListener("notificationclose", function (event) 
    event.notification.close();
    console.log('user has clicked notification close');    
);

application.js 文件:

/// <reference path="scripts/jquery-3.3.1.js" />

try 
var config = 
    apiKey: "your api key",
    authDomain: "you firebase domain",
    databaseURL: "your firbase db url",
    projectId: "your project id",
    storageBucket: "",
    messagingSenderId: "sender id"
;
firebase.initializeApp(config);

    if ('serviceWorker' in navigator && 'PushManager' in window) 
    console.log('Service Worker and Push is supported');

    navigator.serviceWorker
        .register('/firebase-messaging-sw.js')
        .then((swReg) => 
            firebase.messaging().useServiceWorker(swReg);
            askForPermissioToReceiveNotifications();            
        )
        .catch(function (error) 
            console.error('Service Worker Error', error);
            window.alert("Service Worker Error" + error);
        )
 else 
        console.warn('Push messaging is not supported');        
        window.alert("Push messaging is not supported " + (navigator.serviceWorker));    


const askForPermissioToReceiveNotifications = async () => 
    try                     
                    const messaging = firebase.messaging();
                    console.log(messaging);
                    await messaging.requestPermission();
                    const token = await messaging.getToken();                    
                    if (token !== null || token !== 'undefined') 
                        await sendDeviceTokenToServerSide(token);
                                        
                    console.log('Got token : ' + token);
                    messaging.onMessage(function (payload) 
                        console.log('onMessage: ', payload);
                        setTimeout(() => 
                            navigator.serviceWorker.ready.then(function (registration)  
                                var notificationTitle = payload.notification.title;
                                var notificationOptions = 
                                    body: payload.notification.body,
                                    data: payload.data,
                                    icon: payload.notification.icon,
                                    image: payload.data.Image,
                                    requireInteraction: payload.notification.requireInteraction,
                                    tag: payload.notification.tag,
                                    click_action: payload.data.click_action,
                                    requireInteraction: true
                                ;
                                registration.showNotification(notificationTitle, notificationOptions);
                            ,50)
                        );                                                
                    ); 
    
    catch (e)  console.log('error in getting token: ' + e); window.alert("error in getting token: " + e);  
 

function sendDeviceTokenToServerSide(token) 
        $.ajax(
            type: 'POST',
            url: '/Home/StoreToken',
            timeout: 5000000,           
            data:  token: token ,
            success: function (success)                 
                console.log("device token is sent to server");                                
            ,
            error: function (error) 
                console.log("device error sending token to server : " + error);
                window.alert("device error sending token to server : " + error);
            
        );

 catch (e) 
    window.alert("error: " + e);


function GetFcmUserToken(messaging) 
    messaging.onTokenRefresh(function () 
        messaging.getToken()
            .then(function (refreshedToken) 
                console.log('Token refreshed.');               
                return refreshedToken;
            )
            .catch(function (err) 
                console.log('Unable to retrieve refreshed token ', err);
                showToken('Unable to retrieve refreshed token ', err);
            );
    );

【讨论】:

你的代码和我的代码一样。 你的代码在 serviceworker.js/firebase-messaging-sw.js 下对吗? 是的,文件中的其余代码正在运行。我就是无法触发点击处理程序。 当网站同时处于前台和后台或仅在后台时会发生这种情况? 该通知仅在网站处于后台时出现。我认为这种行为是由 Firebase 消息处理的。【参考方案2】:
self.addEventListener('notificationclick', function (event) 
const clickedNotification = event.notification;
// Do something as the result of the notification click
const promiseChain = clients.openWindow(clickedNotification.data.Url);
event.waitUntil(promiseChain);
);

Service Worker js 中的这段代码在 Chrome 桌面和 android 上运行良好。

【讨论】:

以上是关于服务工作者“notificationclick”未触发的主要内容,如果未能解决你的问题,请参考以下文章

远程通知不会触发notificationclick

ServiceWorker 在生命周期后期声称在 notificationclick 事件处理程序中使用 client.navigate

通知点击事件服务工作者

服务工作者 - 等待client.openWindow在postMessage之前完成

Push web api,notificationclick,如何打开桌面客户端而不是打开新的浏览器客户端

Firebase 消息传递服务工作人员点击处理程序不起作用