Подтвердить что ты не робот

Запретить API-интерфейс chrome.notifications скрывать мое уведомление через несколько секунд

Я делаю около 1-2 уведомлений в день, и важно, чтобы пользователь не пропустил его. Есть ли способ удалить автоматическое закрытие и разрешить пользователю вручную закрывать уведомление?

В Вариантах уведомлений я не вижу никаких параметров:

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

4b9b3361

Ответ 1

ОБНОВЛЕНИЕ (2016-05-24):

Xan прокомментировал:

Интересный факт: все это тайное хакерство больше не требуется; см. новый флаг requireInteraction

Это доступно с Chrome 50. Дополнительная информация.


Благодаря комментарию root этот ответ пересматривается с учетом того факта, что событие onClosed не запускается, когда уведомление исчезает (в области уведомлений) через несколько секунд. Это все-таки хакерское решение.


Фон

Вы можете воспользоваться тем фактом, что жизненный цикл уведомления заканчивается одним из следующих событий:

  • onClosed: когда пользователь нажимает на маленький "х" в верхнем правом углу.
  • onClicked: когда пользователь нажимает на тело сообщения (а не "x", а не некоторые кнопки).
  • onButtonClicked: когда пользователь нажимает на одну из кнопок (если есть).

Решение

Предлагаемое решение состоит из следующих шагов:

  • Зарегистрируйте слушателей для всех событий, упомянутых выше.
  • Зарегистрируйте тайм-аут через несколько секунд (например, 30) - после того, как уведомление будет скрыто - это будет удалить и create уведомление (поэтому оно эффективно остается видимым на экране.
  • Если какой-либо из слушателей, установленный на шаге 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"]
}

В background.js:

var pendingNotifications = {};

/* For demonstration purposes, the notification creation
 * is attached to the browser-action `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 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 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 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 (который может иметь цвет и небольшой текст, указывая количество ожидающих уведомлений.
  • Я не рассматривал его, но возможно (и в этом случае также целесообразно) заменить Timeout на chrome.alarms API, а затем преобразовать фоновую страницу в непостоянную (aka event-страница), что сделает ее более дружественной к ресурсам.

Ответ 2

Уведомление теперь имеет (начиная с Chrome 50) свойство requireInteraction, чтобы заставить уведомление оставаться на экране:

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

В onclick вам нужно закрыть уведомление:

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

Ответ 4

Этот ответ устарел; см. этот ответ для актуального решения с флагом requireInteraction (Chrome 50 +).


Существует немного лучшее (но опять же, хакерское) решение.

Когда вы вызываете update в уведомлении, которое изменяет его приоритет, а приоритет равен 0 или выше, уведомление будет повторно показано и таймер для его скрытия reset.

Итак, вы можете показать уведомление с высоким приоритетом (скажем, 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
  }
});

Ответ 5

UPDATE answar: после Chrome 50 добавьте новый атрибут: [requireInteraction: true]!

не использовать chrome.notifications.create

попробуйте использовать var notification= new Notification("New mail from John Doe", { tag: 'msg1', requireInteraction: true});
не будет закрываться.

если хотите закрыть = > notification.close();

ref: http://www.w3.org/TR/notifications/

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