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

use*_*162 18 google-chrome google-chrome-extension

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

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

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

Mat*_*llo 16

通知现在(自Chrome 50起)一个强制通知留在屏幕上的requireInteraction属性:

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

onclick你必须关闭通知:

notification.onclick = function()
{
    this.close();
}
Run Code Online (Sandbox Code Playgroud)


gka*_*pak 12

更新(2016-05-24):

Xan评论说:

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

它可用于Chrome 50. 更多信息.


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


背景

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

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

解决方案

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

  1. 注册上述所有事件的监听器.
  2. 在几秒钟(例如30)之后注册超时 - 在隐藏通知之后 - 将删除并重新创建通知(因此它有效地保持在屏幕上可见.
  3. 如果在步骤1中设置的任何侦听器触发,则表示用户与通知相互作用,因此取消超时(您不需要重新创建通知).

写它很简单,编码需要更多的努力:)这是我用来实现上述内容的示例代码:

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"]
}
Run Code Online (Sandbox Code Playgroud)

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));
    }
});
Run Code Online (Sandbox Code Playgroud)

最后的说明:

  • 如果您的通知非常重要,您应该实施"恢复"机制,例如浏览器操作系统崩溃或突然终止.例如依靠更持久存储(localStorage,chrome.storageAPI等),上延伸部恢复待处理通知/浏览器的启动等.
  • 出于"用户友好性"的原因,对待处理通知的总数进行限制可能是个好主意.如果您的待处理通知在任何给定时刻超过,例如3,您可以将其替换为通知有待处理通知的通知,并将用户定向到您列出所有通知的页面.(代码会相当复杂,但对于用户来说嘿嘿,对吧?;)
  • 在用户决定处理它们之前,不要试图保持通知在屏幕上可见,最好使用徽章(可以有颜色和小文本 - 表示待处理通知的数量.
  • 我没有调查过,但是有可能(在这种情况下也是可行的)Timeoutchrome.alarmsAPI替换's 然后将后台页面转换为非持久性(也就是事件页面),这将是使它更加资源友好.