使用 Web Notifications

這是一個實驗中的功能
此功能在某些瀏覽器尚在開發中,請參考兼容表格以得到不同瀏覽器用的前輟。

摘要

Web Notifications API 可將通知傳送至頁面以外的系統層級並顯示通知。因此即使 Web Apps 處於閒置狀態,亦可傳送資訊予使用者。絕佳範例之一,就是在使用其他 Apps 時,Web Mail App 同樣可通知使用者已接收到新郵件。

要求權限

網頁內容

在 Apps 傳送通知之前,使用者必須先許可 Apps 的動作。只要 APIs 嘗試予網頁之外的東西互動,均必須先獲得使用者的授權。如此可避免濫發通知而影響使用經驗。

透過 Notification.permission 唯讀屬性,要傳送通知的 Apps 將檢查目前的授權狀態。此屬性共有 3 組參數:

  • default:使用者尚未給予任何權限 (因此不會顯示任何通知)
  • granted:使用者允許接收到 Apps 的通知
  • denied:使用者拒絕接收 Apps 的通知

注意:Chrome 與 Safari 尚未建構 permission 屬性。

若使用者尚未給予權限,則 Apps 必須透過 Notification.requestPermission() 函式讓使用者選擇,接著由此函式接收 1 組回呼 (Callback) 函式作為參數;而該回呼函式則提供使用者是否授權的資訊。

以下為啟動 Apps 時要求權限的常用範例:

window.addEventListener('load', function () {
  Notification.requestPermission(function (status) {
    // This allows to use Notification.permission with Chrome/Safari
    if (Notification.permission !== status) {
      Notification.permission = status;
    }
  });
});

注意:Chrome 不允許於載入事件中呼叫 Notification.requestPermission() (參閱 issue 274284)。

已安裝的 Apps

在安裝 Apps 之後,若於 Apps 的 manifest 檔案中直接添加權限,即可省去再次向使用者要求權限的動作。

permissions: {
  "desktop-notification": {
    "description: "Allows to display notifications on the user's desktop.
  }
}

建立通知

透過 Notification 建構子 (Constructor) 即可建立通知。此建構子包含 1 組標題,可於通知內顯示;另有如 icon 或文字 body數個選項,可強化通知的內容。

在建立實體 (Instantiated) 之後,就會儘快顯示通知。若要追蹤通知的目前狀態,必須在 Notification 的實體階層觸發 4 個事件:

  • show:對使用者顯示通知之後,隨即觸發
  • click:使用者點擊通知之後,隨即觸發
  • close:關閉通知之後,隨即觸發
  • error:通知發生任何錯誤 (大多數是因為某種情況而未顯示通知),隨即觸發

而透過 onshowonclickonclose,或 onerror 等事件處理器 (Event handler),即可追蹤這些事件。由於 Notification 是繼承 EventTarget 而來,因此亦可使用 addEventListener() 函式。

注意:Firefox 與 Safari 並未遵守 close 事件的規格。此規格雖然規定「僅限使用者能關閉通知」,但 Firefox 與 Safari 卻可於數分鐘後自動關閉通知。因此不一定是由使用者關閉通知。

此規格並明確規定「應透過 Notification.close() 函式,於應用程式層級完成自動關閉通知」。範例程式碼如下:

var n = new Notification("Hi!");
n.onshow = function () {
  setTimeout(n.close, 5000);
}

簡易範例

先假設下列基本 HTML:

<button>Notify me!</button>

則能以這種方法處理通知:

window.addEventListener('load', function () {
  // At first, let's check if we have permission for notification
  // If not, let's ask for it
  if (Notification && Notification.permission !== "granted") {
    Notification.requestPermission(function (status) {
      if (Notification.permission !== status) {
        Notification.permission = status;
      }
    });
  }
  var button = document.getElementsByTagName('button')[0];
  button.addEventListener('click', function () {
    // If the user agreed to get notified
    if (Notification && Notification.permission === "granted") {
      var n = new Notification("Hi!");
    }
    // If the user hasn't told if he wants to be notified or not
    // Note: because of Chrome, we are not sure the permission property
    // is set, therefore it's unsafe to check for the "default" value.
    else if (Notification && Notification.permission !== "denied") {
      Notification.requestPermission(function (status) {
        if (Notification.permission !== status) {
          Notification.permission = status;
        }
        // If the user said okay
        if (status === "granted") {
          var n = new Notification("Hi!");
        }
        // Otherwise, we can fallback to a regular modal alert
        else {
          alert("Hi!");
        }
      });
    }
    // If the user refuses to get notified
    else {
      // We can fallback to a regular modal alert
      alert("Hi!");
    }
  });
});

現場測試結果

若無法顯示,可至本文右上角「Language」切換回英文原文觀看。

處理多筆通知

某些情況下 (如某個即時訊息 App 持續通知每一筆進來的訊息),使用者可能會接收大量的通知。為了避免太多非必要訊息擠爆使用者的桌面,則應該讓等待中的通知進入佇列。

將標籤添加至任何新的通知,即可達到佇列效果。若通知擁有相同的標籤且尚未顯示,則新通知就會取代先前的通知;反之,若已顯示了相同標籤的通知,就會關閉先前的通知而顯示新通知。

標籤範例

先假設下列基本 HTML:

<button>Notify me!</button>

則能以下列方式處理多筆通知:

window.addEventListener('load', function () {
  // At first, let's check if we have permission for notification
  // If not, let's ask for it
  if (Notification && Notification.permission !== "granted") {
    Notification.requestPermission(function (status) {
      if (Notification.permission !== status) {
        Notification.permission = status;
      }
    });
  }
  var button = document.getElementsByTagName('button')[0];
  button.addEventListener('click', function () {
    // If the user agreed to get notified
    // Let's try to send ten notifications
    if (Notification && Notification.permission === "granted") {
      for (var i = 0; i < 10; i++) {
        // Thanks to the tag, we should only see the "Hi! 10" notification
        var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
      }
    }
    // If the user hasn't told if he wants to be notified or not
    // Note: because of Chrome, we are not sure the permission property
    // is set, therefore it's unsafe to check for the "default" value.
    else if (Notification && Notification.permission !== "denied") {
      Notification.requestPermission(function (status) {
        if (Notification.permission !== status) {
          Notification.permission = status;
        }
        // If the user said okay
        if (status === "granted") {
          for (var i = 0; i < 10; i++) {
            // Thanks to the tag, we should only see the "Hi! 10" notification
            var n = new Notification("Hi! " + i, {tag: 'soManyNotification'});
          }
        }
        // Otherwise, we can fallback to a regular modal alert
        else {
          alert(Hi!");
        }
      });
    }
    // If the user refuses to get notified
    else {
      // We can fallback to a regular modal alert
      alert(Hi!");
    }
  });
});

現場測試結果

若無法顯示,可至本文右上角「Language」切換回英文原文觀看。

規格

Specification Status Comment
Notifications API Living Standard Initial specification.

瀏覽器相容性

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidSafari on iOSSamsung Internet
Basic supportChrome Full support 22
Notes
Full support 22
Notes
Notes Before Chrome 22, the support for notification followed an old prefixed version of the specification and used the navigator.webkitNotifications object to instantiate a new notification. Before Chrome 32, Notification.permission was not supported. Before Chrome 42, service worker additions were not supported. Starting in Chrome 49, notifications do not work in incognito mode.
Full support 5
Prefixed
Prefixed Implemented with the vendor prefix: -webkit-
Edge Full support YesFirefox Full support 22
Full support 22
Full support 4
Prefixed
Prefixed Implemented with the vendor prefix: -moz-
IE No support NoOpera Full support 25Safari Full support 6WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support 22
Full support 22
Full support 4
Prefixed
Prefixed Implemented with the vendor prefix: -webkit-
Opera Android Full support YesSafari iOS No support NoSamsung Internet Android ?
Available in workersChrome Full support 45Edge Full support YesFirefox Full support 41IE No support NoOpera Full support 32Safari ? WebView Android No support NoChrome Android Full support 45Edge Mobile Full support YesFirefox Android Full support 41Opera Android Full support 32Safari iOS No support NoSamsung Internet Android ?
Secure contexts onlyChrome Full support 62Edge ? Firefox ? IE No support NoOpera Full support 49Safari ? WebView Android No support NoChrome Android Full support 62Edge Mobile ? Firefox Android ? Opera Android Full support 49Safari iOS No support NoSamsung Internet Android ?
Notification() constructorChrome Full support 22
Full support 22
Full support 5
Prefixed
Prefixed Implemented with the vendor prefix: webkit
Edge Full support YesFirefox Full support 22
Full support 22
Full support 4
Prefixed
Prefixed Implemented with the vendor prefix: moz
IE No support NoOpera Full support 25Safari Full support 6WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support 22
Full support 22
Full support 4
Prefixed
Prefixed Implemented with the vendor prefix: moz
Opera Android Full support YesSafari iOS No support NoSamsung Internet Android ?
actionsChrome Full support 53Edge Full support 18Firefox No support NoIE No support NoOpera Full support 39Safari ? WebView Android No support NoChrome Android Full support 53Edge Mobile No support NoFirefox Android No support NoOpera Android Full support 39Safari iOS No support NoSamsung Internet Android ?
badgeChrome Full support 53Edge Full support 18Firefox No support NoIE No support NoOpera Full support 39Safari ? WebView Android No support NoChrome Android Full support 53Edge Mobile No support NoFirefox Android No support NoOpera Android Full support 39Safari iOS No support NoSamsung Internet Android ?
bodyChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
dataChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
dirChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
iconChrome Full support 22
Full support 22
Full support 5
Prefixed
Prefixed Implemented with the vendor prefix: -webkit-
Edge ? Firefox Full support 22
Full support 22
Full support 4
Prefixed
Prefixed Implemented with the vendor prefix: -moz-
IE No support NoOpera Full support 25Safari No support NoWebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support 22
Full support 22
Full support 4
Prefixed
Prefixed Implemented with the vendor prefix: -moz-
Opera Android Full support YesSafari iOS No support NoSamsung Internet Android ?
imageChrome Full support 53Edge Full support 18Firefox No support NoIE No support NoOpera Full support 40Safari ? WebView Android No support NoChrome Android Full support 53Edge Mobile ? Firefox Android No support NoOpera Android Full support 40Safari iOS No support NoSamsung Internet Android ?
langChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
maxActionsChrome Full support YesEdge Full support 18Firefox No support NoIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android No support NoOpera Android ? Safari iOS No support NoSamsung Internet Android ?
onclickChrome Full support YesEdge ? Firefox No support NoIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android No support NoOpera Android ? Safari iOS No support NoSamsung Internet Android ?
oncloseChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
onerrorChrome Full support YesEdge ? Firefox No support NoIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android No support NoOpera Android ? Safari iOS No support NoSamsung Internet Android ?
onshowChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
permissionChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
renotifyChrome Full support 50Edge No support NoFirefox No support NoIE No support NoOpera Full support 37Safari No support NoWebView Android No support NoChrome Android Full support 50Edge Mobile No support NoFirefox Android No support NoOpera Android Full support 37Safari iOS No support NoSamsung Internet Android ?
requireInteractionChrome Full support YesEdge Full support 17Firefox No support NoIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile No support NoFirefox Android No support NoOpera Android ? Safari iOS No support NoSamsung Internet Android ?
silentChrome Full support 43Edge Full support 17Firefox No support NoIE No support NoOpera Full support 30Safari No support NoWebView Android No support NoChrome Android Full support 43Edge Mobile No support NoFirefox Android No support NoOpera Android Full support 30Safari iOS No support NoSamsung Internet Android ?
tagChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
timestampChrome Full support YesEdge Full support 17Firefox No support NoIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile No support NoFirefox Android No support NoOpera Android ? Safari iOS No support NoSamsung Internet Android ?
titleChrome Full support YesEdge ? Firefox No support NoIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android No support NoOpera Android ? Safari iOS No support NoSamsung Internet Android ?
vibrateChrome Full support 53Edge No support NoFirefox No support NoIE No support NoOpera Full support 39Safari ? WebView Android No support NoChrome Android Full support 53Edge Mobile No support NoFirefox Android No support NoOpera Android Full support 39Safari iOS No support NoSamsung Internet Android ?
closeChrome Full support YesEdge ? Firefox Full support YesIE No support NoOpera ? Safari ? WebView Android No support NoChrome Android Full support YesEdge Mobile ? Firefox Android Full support YesOpera Android ? Safari iOS No support NoSamsung Internet Android ?
requestPermissionChrome Full support 46Edge ? Firefox Full support 47IE No support NoOpera Full support 40Safari ? WebView Android No support NoChrome Android Full support 46Edge Mobile ? Firefox Android Full support YesOpera Android Full support 40Safari iOS No support NoSamsung Internet Android ?

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
See implementation notes.
See implementation notes.
Requires a vendor prefix or different name for use.
Requires a vendor prefix or different name for use.

另可參閱