几秒钟后,阻止chrome.notifications API隐藏我的通知

时间:2013-12-02 11:14:18

标签: google-chrome google-chrome-extension

我每天要做1-2次通知,重要的是用户不要错过它。有没有办法删除自动关闭,只允许用户手动关闭通知?

我在通知选项中看不到任何选项:

http://developer.chrome.com/extensions/notifications.html#type-NotificationOptions

5 个答案:

答案 0 :(得分:15)

通知现在(从Chrome 50开始)requireInteraction property强制通知留在屏幕上:

var notification = new Notification("TITLE", {
          icon: 'assets/res/icon.png',
          body: "MESSAGE",
          requireInteraction: true     
});

onclick中,您必须关闭通知:

notification.onclick = function()
{
    this.close();
}

答案 1 :(得分:12)

更新(2016-05-24):

Xan commented

  有趣的事实:不再需要所有这些神秘的黑客行为;看到新的requireInteraction标志

自Chrome 50以来可用。More info


感谢root的评论,修改了这个答案,以解释当几秒钟后通知消失(进入notigications区域)时onClosed事件未被触发的事实。这仍然是一种 hacky 解决方案。


背景

您可以利用以下事实:通知的生命周期以下列事件之一结束:

  • onClosed :当用户点击右上角的小'x'时。
  • onClicked :当用户点击邮件正文时(不是“x”,而不是某个按钮)。
  • onButtonClicked :当用户点击其中一个按钮(如果有)时。

解决方案

建议的解决方案包括以下步骤:

  1. 为上述所有事件注册听众。
  2. 在隐藏通知后几秒钟(例如30)之后注册超时 - delete 并重新 create 通知(因此它有效地保持在屏幕上可见。
  3. 如果在步骤1中设置的任何侦听器触发,则表示用户与通知相互作用,因此取消超时(您无需重新创建通知)。
  4. 写它很简单,编码需要更多努力:) 以下是我用来实现上述内容的示例代码:

    manifest.json

    {
        "manifest_version": 2,
        "name":    "Test Extension",
        "version": "0.0",
    
        "background": {
            // We need this for the `Timeout` - see notes below
            "persistent": true,
            "scripts": ["background.js"]
        },
    
        "browser_action": {
            "default_title": "Test Extension"
            "default_icon": {
                "19": "img/icon19.png",
                "38": "img/icon38.png"
            },
        },
    
        "permissions": ["notifications"]
    }
    

    background.js

    var pendingNotifications = {};
    
    /* For demonstration purposes, the notification creation
     * is attached to the browser-action's `onClicked` event.
     * Change according to your needs. */
    chrome.browserAction.onClicked.addListener(function() {
        var dateStr = new Date().toUTCString();
        var details = {
            type:    "basic",
            iconUrl: "/img/notifIcon.png",
            title:   "REMINDER",
            message: dateStr + "\n\n"
                     + "There is one very important matter to attend to !\n"
                     + "Deal with it now ?",
            contextMessage: "Very important stuff...",
            buttons: [
                { title: "Yes" }, 
                { title: "No"  }
            ]
        };
        var listeners = {
            onButtonClicked: function(btnIdx) {
                if (btnIdx === 0) {
                    console.log(dateStr + ' - Clicked: "yes"');
                } else if (btnIdx === 1) {
                    console.log(dateStr + ' - Clicked: "no"');
                }
            },
            onClicked: function() {
                console.log(dateStr + ' - Clicked: "message-body"');
            },
            onClosed: function(byUser) {
                console.log(dateStr + ' - Closed: '
                            + (byUser ? 'by user' : 'automagically (!?)'));
            }
        };
    
        /* Create the notification */
        createNotification(details, listeners);
    });
    
    /* Create a notification and store references
     * of its "re-spawn" timer and event-listeners */
    function createNotification(details, listeners, notifId) {
        (notifId !== undefined) || (notifId = "");
        chrome.notifications.create(notifId, details, function(id) {
            console.log('Created notification "' + id + '" !');
            if (pendingNotifications[id] !== undefined) {
                clearTimeout(pendingNotifications[id].timer);
            }
    
            pendingNotifications[id] = {
                listeners: listeners,
                timer: setTimeout(function() {
                    console.log('Re-spawning notification "' + id + '"...');
                    destroyNotification(id, function(wasCleared) {
                        if (wasCleared) {
                            createNotification(details, listeners, id);
                        }
                    });
                }, 10000)
            };
        });
    }
    
    /* Completely remove a notification, cancelling its "re-spawn" timer (if any)
     * Optionally, supply it with a callback to execute upon successful removal */
    function destroyNotification(notifId, callback) {
    
        /* Cancel the "re-spawn" timer (if any) */
        if (pendingNotifications[notifId] !== undefined) {
            clearTimeout(pendingNotifications[notifId].timer);
            delete(pendingNotifications[notifId]);
        }
    
        /* Remove the notification itself */
        chrome.notifications.clear(notifId, function(wasCleared) {
            console.log('Destroyed notification "' + notifId + '" !');
    
            /* Execute the callback (if any) */
            callback && callback(wasCleared);
        });
    }
    
    /* Respond to the user's clicking one of the buttons */
    chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
        if (pendingNotifications[notifId] !== undefined) {
            var handler = pendingNotifications[notifId].listeners.onButtonClicked;
            destroyNotification(notifId, handler(btnIdx));
        }
    });
    
    /* Respond to the user's clicking on the notification message-body */
    chrome.notifications.onClicked.addListener(function(notifId) {
        if (pendingNotifications[notifId] !== undefined) {
            var handler = pendingNotifications[notifId].listeners.onClicked;
            destroyNotification(notifId, handler());
        }
    });
    
    /* Respond to the user's clicking on the small 'x' in the top right corner */
    chrome.notifications.onClosed.addListener(function(notifId, byUser) {
        if (pendingNotifications[notifId] !== undefined) {
            var handler = pendingNotifications[notifId].listeners.onClosed;
            destroyNotification(notifId, handler(byUser));
        }
    });
    

    最后说明:

    • 如果您的通知非常重要,您应该实施“恢复”机制,例如浏览器操作系统崩溃或突然终止。例如。依赖更持久的存储( localStorage chrome.storage API 等),在扩展程序/浏览器启动时恢复待处理通知等。
    • 出于“用户友好性”原因,对待处理通知总数进行限制可能是个好主意。如果您的待处理通知在任何给定时刻超过,例如3,您可以将其替换为通知有待处理通知的通知,并将用户定向到您列出所有通知的页面。 (代码会变得相当复杂,但对用户来说嘿嘿,对吧?;)
    • 在使用 Badge (可以有颜色和一个小文本 - 表示待处理通知的数量。
    • 我没有调查过,但是有可能(在这种情况下也是可行的)用 chrome.alarms API <替换Timeout / strong>然后将背景页面转换为非持久性(又名 event-page ),这将使其更具资源友好性。

答案 2 :(得分:4)

这个答案已过时;有关requireInteraction标记(Chrome 50 +)的最新解决方案,请参阅this answer


有一个稍微好一点(但同样是hacky)的解决方案。

当您在更改优先级的通知上调用update且优先级为0或更高时,将重新显示通知并将隐藏它的计时器重置。

因此,您可以显示具有高优先级的通知(例如,2),然后以短于时间的间隔重复此操作以隐藏通知:

chrome.notifications.update(id, {priority : 1}, function(wasUpdated) {
  if(wasUpdated) {
    chrome.notifications.update(id, {priority : 2}, function() {});
  } else {
    // Notification was fully closed; either stop updating or create a new one
  }
});

答案 3 :(得分:4)

UPDATE回答:在Chrome 50之后,请添加新属性:[requireInteraction:true]!

请勿使用chrome.notifications.create

尝试使用var notification= new Notification("New mail from John Doe", { tag: 'msg1', requireInteraction: true});
不会关闭。

如果想关闭=&gt; notification.close();

参考:http://www.w3.org/TR/notifications/

https://developer.mozilla.org/en-US/docs/Web/API/notification/requireInteraction

答案 4 :(得分:3)

webkit通知似乎在屏幕上更持久,尽管它们存在相反的问题 - 如何将它们隐藏到sys托盘中。

http://developer.chrome.com/extensions/desktop_notifications.html