Notifications API

Living Standard — Last Updated

参与:
file a bug (open bugs)
whatwg@whatwg.org (archives)
IRC: #whatwg on Freenode
提交:
https://github.com/whatwg/notifications/commits
@notifyapi

Abstract

该标准定义了一个 API 来给终端用户显示通知,通常显示在顶层浏览上下文视口。该 API 被设计成与现有的 Notifications 系统兼容,但依然是平台独立的。

内容提纲

1. 术语

本规范中使用的一些术语取自DOM、Fetch、HTML、IDL、URL 和 振动 API 标准。 [DOM] [FETCH] [HTML] [WEBIDL] [URL] [VIBRATION]

2. Notifications

notification 是事件发生的抽象表示,如信息发出。

一个 notification 有一个关联的 DOMString 类型的 title

一个 notification 有一个关联的 DOMString 类型的 body

一个 notification 有一个关联的 direction 其值是 auto, ltr, and rtl三者之一。

一个 notification 有一个关联的 DOMString 类型的 language ,其值是一个有效的 BCP 47 语言标记或空字符串。

一个 notification 有一个关联的 DOMString 类型的 tag

一个 notification 有一个关联的 data

一个 notification 有一个关联的 origin

一个 notification 有一个关联的未被设置的 renotify preference flag。 设置该标志表示运行replace steps后,最终用户会被警告。

一个 notification 有一个关联的未被设置的 silent preference flag。设置该标志表示不接收声音或者振动通知。

一个 notification 有一个关联的未被设置的 screen off preference flag。设置该标志表示设备屏幕不会被启用。

一个 notification 有一个关联的未被设置的 sticky preference flag。设置该标志表示最终用户将不能很容易地清除 notification 仅适用于persistent notifications.

一个 notification 可以 有关联的 icon URL, icon resource, sound URL, sound resource, vibration pattern,和 service worker registration.

不鼓励开发者通过图标、声音或振动模式来给最终用户传达信息;除非这些信息 是最终用户可以访问的。

一个 non-persistent notification 是没有关联 service worker registrationnotification

一个 persistent notification 是关联了 service worker registrationnotification


create a notification,给定一个titleoptions,执行这些步骤:

  1. notification 是一个新的 notification.

  2. 如果 optionssilent 为 true, 那么 optionssound 出现时或者 optionsvibrate 出现时, throw 一个 TypeError 异常。

  3. 如果 optionsrenotify 为 true 并且 optionstag 为空字符串,那么 throw 一个 TypeError 异常。

  4. 设置 notificationdata 为一个optionsdatastructured clone。重新抛出任何异常。

  5. 设置 notificationtitleoptionstitle.

  6. 设置 notificationdirectionoptionsdir.

  7. 如果 optionslang 是一个有效的 BCP 47 语言标记或空字符串, 设置 notificationlanguageoptionslang;否则将之设置为空字符串。 [LANG]

  8. 设置 notificationoriginentry settings objectorigin

  9. 设置 notificationbodyoptionsbody.

  10. 设置notificationtagoptionstag.

  11. baseURLentry settings object 指定的 API 基础 URL。 或现任?

  12. 如果 options 存在 icon ,用 baseURL parse 它;解析无误时,设置 notificationicon URL 为该解析值。(否则 icon URL 未设置。)

  13. 如果 optionssound 存在, 用 baseURL parse 它;解析无误时,设置 notificationsound URL 为该解析值。(否则 sound URL 未设置。)

  14. 如果 optionsvibrate 存在, validate and normalize 它, 并设置 notificationvibration pattern 为该规范化值。 (否则vibration pattern未设置。)

  15. 如果 optionsrenotify 为 true,设置 notificationrenotify preference flag.

  16. 如果 optionssilent 为 true,设置 notificationsilent preference flag.

  17. 如果 optionsnoscreen 为 true,设置 notificationscreen off preference flag.

  18. 如果 optionssticky 为 true,设置 notificationsticky preference flag.

  19. 返回 notification.

2.1. 生命周期与 UI 整合

用户代理必须保留一个由零或多个 notifications 组成的 list of notifications

用户代理应该在创建 non-persistent notification 之后的几秒种内执行close steps

用户代理不应该在平台的“通知中心”(如果有的话)显示 non-persistent notification

用户代理应该保持 persistent notifications,直至被移除出list of notifications

一个 persistent notification 可通过其 Notification 对象来调用 close() 方法。

用户代理应该在平台的“通知中心”(如果有的话)显示 persistent notification

2.2. 许可模式

Notifications 当且仅当被用户(或用户代理)授予permission时,才能被显示。 为给定 origin 显示 notificationspermission 是下面三个字符串之一:

"default"

相当于 "denied",但用户没有作出明确的选择。

"denied"

意味着用户不希望被 notifications.

"granted"

意味着可以显示 notifications

"default" 从不会等同于 "granted"。如果那样 的话, "granted" 会被滥用,应用程序再也不必请求 permission

2.3. 方向

本节所使用的术语等同于 HTML 规范中渲染部分所使用的。 [HTML]

期望用户代理使用 Unicode 语义来解析 notificationtitlebody中的文本。展示它们时,应视之为由双向 算法规则P1、P2和P3所定义的一个或多个双向算法段落组成的独立集合,例如包括支持换行 符 U+000A (LF) 带来的段落分割。对 titlebody中的 每一段,notificationdirection 属性在其值非 "auto"时,将覆盖双向算法P2和P3规则。 [BIDI]

2.4. 语言

notificationlanguage 属性指定了 notificationtitlebody的主要语言。语言属性值要么是一个有效的 BCP 47 语言标记,要么是一个空 字符串。空字符串表示主要语言是未知的。 [LANG]

2.5. 资源

对给定 notification notificationfetch steps 是:

  1. 如果通知平台支持图标,并且通知设置了icon URL,则 fetch notificationicon URL

    然后, in parallel:

    1. 等待 response.

    2. 如果 responseinternal responsetypedefault,试图作为图像解码该资源。

    3. 如果平台支持该图像格式,设置 notificationicon resource 为该解码后的资源。(否则 notification 没有 icon resource。)

  2. 如果通知平台支持声音,并且通知设置了 sound URL ,则 fetch notificationsound URL

    然后, in parallel

    1. 等待 response

    2. 如果 responseinternal responsetypedefault,试图作为声音解码该资源。

    3. 如果平台支持该声音格式,设置 notificationsound resource 为解码后的资源。(否则, notification 没有 sound resource。)

2.6. 显示通知

对给定 notification notification ,其show steps是:

  1. 如果 list of notifications 里存在某一 notification, 其 tag 非空字符串且等于 notificationtag,其 originnotificationoriginsame origin, 那么对该 notification 执行 replace steps,而后终止这些步骤。

  2. 否则,对 notification 执行 display steps

2.7. 激活通知

当用户激活 notification notification 时,假设底层通知平台支持激活,用户代理必须(除非另有规定)执行这些步骤:

  1. 如果 notificationpersistent notification,执行这些子步骤:

    1. callbackglobal 所调用的一种算法,对给定 global 上的 notification fires a service worker notification event 命名为 notificationclick

    2. 而后对 notificationservice worker registrationcallback 运行 Handle Functional Event

  2. 否则,queue a task 来执行这些子步骤:

    1. 在表示 notificationNotification 对象上 Fire an event 属性为 click,其 cancelable 属性初始化为 true。

      鼓励用户代理在 click 事件监听器中使用 window.focus()

    2. 如果没有设置该 eventcanceled flag,用户 代理应该聚焦 notification 相关的 browsing context 的 viewport。

纵观整个网络平台,“激活”被故意名不副实地称为“点击”。

2.8. 关闭通知

不论是底层通知平台还是用户,在关闭 notification 时, 都必须执行 close steps

对给定 notification ,其 close steps 是:

  1. 如果 notification 不在 中,终止这些步骤。

  2. list of notifications 中删除 notification

2.9. 展示通知

对给定 given notification,其display steps 是:

  1. 等待所有的 fetches 完成,并且如果有的话,设置好 notificationicon resourcesound resource

  2. 在设备上展示 notification(例如通过调用相应的通知平台)。

    同时,如果有的话,播放 notificationsound resource,使用 notificationvibration pattern perform vibration

  3. 追加 notificationlist of notifications

2.10. 更换通知

old notification 更换为 new 到, replace steps 是:

  1. 等待所有的 fetches 完成,并且如果有的话,设置好 notificationicon resourcesound resource

  2. list of notifications 相同的位置,将 old 更换为 new

    如果通知平台不支持更换要求,那么可对 old 运行 close steps 而后对 new 运行 display steps

    强烈建议通知平台支持原生更换,它要好得多。

3. API

[Constructor(DOMString title, optional NotificationOptions options),
 Exposed=(Window,Worker)]
interface Notification : EventTarget {
  static readonly attribute NotificationPermission permission;
  [Exposed=Window] static void requestPermission(optional NotificationPermissionCallback callback);

  attribute EventHandler onclick;
  attribute EventHandler onerror;

  readonly attribute DOMString title;
  readonly attribute NotificationDirection dir;
  readonly attribute DOMString lang;
  readonly attribute DOMString body;
  readonly attribute DOMString tag;
  readonly attribute USVString icon;
  readonly attribute USVString sound;
  // 目前还没有暴露振动属性;见 bug 23682
  readonly attribute boolean renotify;
  readonly attribute boolean silent;
  readonly attribute boolean noscreen;
  readonly attribute boolean sticky;
  [SameObject] readonly attribute any data;

  void close();
};

dictionary NotificationOptions {
  NotificationDirection dir = "auto";
  DOMString lang = "";
  DOMString body = "";
  DOMString tag = "";
  USVString icon;
  USVString sound;
  VibratePattern vibrate;
  boolean renotify = false;
  boolean silent = false;
  boolean noscreen = false;
  boolean sticky = false;
  any data = null;
};

enum NotificationPermission {
  "default",
  "denied",
  "granted"
};

callback NotificationPermissionCallback = void (NotificationPermission permission);

enum NotificationDirection {
  "auto",
  "ltr",
  "rtl"
};

一个 non-persistent notification 由一个 Notification 对象来表示,并且可以通过 Notificationconstructor来创建

一个 persistent notification 由零或多个 Notification 对象来表示,并且可以通过 showNotification() 方法来创建。

3.1. 垃圾回收

Notification 对象相对应的 notificationlist of notifications 时,该对象有一个 typeclickerrorevent listener,那么该 Notification 对象 一定不能被垃圾回收。

3.2. 构造函数

当调用 Notification(title, options) 构造函数时,必须(除非另有说明)执行这些步骤:

  1. 如果 options 存在 stickythrow TypeError 异常。

  2. 如果 entry settings objectglobal object 是一个 ServiceWorkerGlobalScope 对象, throw 一个 TypeError 异常。

  3. notification 是给定 titleoptions 之后 creating a notification 的。重新抛出任一异常。

  4. n 是与 notification 相关联的新 Notification .

  5. in parallel 执行这些子步骤:

    1. 如果对 notificationoriginpermission 不是 "granted",在 nqueue a taskfire an event 命名为 error,并终止这些步骤。

    2. notification 执行 fetch steps

    3. notification 执行 show steps

  6. 返回 n.

3.3. 静态成员

获取静态属性 permission 的值必须返回对 entry settings objectoriginpermission

当调用静态方法 requestPermission(callback) 时,必须执行这些步骤:

  1. 返回,但依然 in parallel 执行这些子步骤:

  2. permission 是对 entry settings objectoriginpermission

  3. 如果 permission 是 "default",询问用户对 entry settings objectorigin 进行显示通知是否可接受。如果可接受,设置许可为 "granted",否则设置许可为 "denied" 。

  4. Queue a task 来设置 permissionentry settings objectoriginpermission,并且当存在 callback 时将 permission 作为参数调用该 callback 。如果有任何异常抛出, report the exception.

设计时,通知平台是迄今为止询问用户许可比较有意义的实例。其他 API 的规范没有必要使用该模式,相反可使用 更多合适的替代品之一。

3.4. 对象成员

Notification 对象必须作为属性支持下列 event handlers (及其相应的 event handler event types)。

事件处理程序 事件处理事件类型
onclick click
onerror error

当调用 close() 方法时, 必须对 notification 执行 close steps

获取 title 属性值必须 返回 notificationtitle

获取 dir 属性值必须 返回 notificationdirection

获取 lang 属性值必须 返回 notificationlanguage

获取 body 属性值必须 返回 notificationbody

获取 tag 属性值必须 返回 notificationtag

获取 icon 属性值必须 返回 notificationicon URL, serialized, ,或者当 notification 没有 icon URL 时返回空字符串。

获取 sound 属性值必须 返回 notification’s sound URL, serialized,或者当 notificationsound URL时 返回空字符串。

获取 renotify 属性值必须 返回 notification’s renotify preference flag

获取 silent 属性值必须 返回 notificationsilent preference flag

获取 noscreen 属性值必须 返回 notificationscreen off preference flag.

获取 sticky 属性值必须 返回 notificationsticky preference flag

获取 data 属性值必须 返回 notificationdatastructured clone

3.5. 示例

3.5.1. 使用事件

开发者可以使用 Notification 对象在其生命周期内发出的事件来产生所需要的行为。

当用户激活一个通知时会触发 click 事件。

var not = new Notification("Gebrünn Gebrünn by Paul Kalkbrenner", { icon: "newsong.svg", tag: "song" })
notification.onclick = function() { displaySong(this) }

3.5.2. 多实例使用 tag 成员

Web 应用程序常常在多实例中进行并发操作,比如用户在多个浏览器标签中打开一个邮件 应用程序。由于桌面是一种共享资源,通知 API 通过 tag 成员提供一种很 容易协调的方式进行通知。

表示相同概念的事件可以使用相同的标记,当两个通知同时显示时,用户只会收到一个通知。

实例 1                | 实例 2
                                             |
// 有个新邮件的通知实例                         |
new Notification("New mail from John Doe",   |
                 { tag: 'message1' });       |
                                             |
                                             |  // 稍后该实例通知有个新邮件。
                                             |  new Notification("New mail from John Doe",
                                             |                   { tag: 'message1' });

如果用户代理遵循这里的算法,这种情况的结果就是,用户收到 单一的 通知 "New mail from John Doe".

3.5.3. 单实例使用 tag 成员

单实例应用程序也可以使用 tag成员来尽可能保持其通知的最新状态变化。

例如,Alice 和 Bob 正在使用一个聊天应用程序,当 Alice 空闲时 Bob 发送了多条信息, 应用程序可能更倾向于 Alice 没有看到每个消息的通知界面。

// Bob 说 "Hi"
new Notification("Bob: Hi", { tag: 'chat_Bob' });

// Bob 说 "Are you free this afternoon?"
new Notification("Bob: Hi / Are you free this afternoon?", { tag: 'chat_Bob' });

这种情况的结果就是单一的通知;第二条消息会替换第一条消息,因为它们具有 相同的标签。在该队列通知(先进先出)平台,使用标签允许通知保持其在队列中的位置。 在总是最先显示最新通知的平台里,也可以使用 close() 方法实现类似的结果。

4. 服务线程 API

dictionary GetNotificationOptions {
  DOMString tag = "";
};

partial interface ServiceWorkerRegistration {
  Promise<void> showNotification(DOMString title, optional NotificationOptions options);
  Promise<sequence<Notification>> getNotifications(optional GetNotificationOptions filter);
};

[Constructor(DOMString type, optional NotificationEventInit eventInitDict),
 Exposed=ServiceWorker]
interface NotificationEvent : ExtendableEvent {
  readonly attribute Notification notification;
};

dictionary NotificationEventInit : ExtendableEventInit {
  required Notification notification;
};

partial interface ServiceWorkerGlobalScope {
  attribute EventHandler onnotificationclick;
};

当调用 showNotification(title, options) 方法时,必须执行这些步骤:

  1. promise 是一个新的 promise.

  2. notification 是给定 titleoptions 以后所 creating a notification的。重新抛出任何异常。

  3. 如果 context objectactive worker 是 null,拒绝 promise 并抛出 TypeError 异常。

  4. 设置 notificationservice worker registration 为该 context object

  5. in parallel 执行这些子步骤:

    1. 如果对 notificationoriginpermission 不是 "granted",拒绝 promise 并抛出 TypeError 异常,而后终止这些子步骤。

    2. 否则,用 undefined 处理 promise

    3. notification 执行 fetch steps

    4. notificationshow steps 执行

  6. 返回 promise

当调用 getNotifications(filter) 方法时,必须执行这些步骤:

  1. promise 是一个新的 promise。

  2. in parallel执行这些子步骤:

    1. tagfiltertag

    2. notifications 是所有那些在 list of notifications 中, 其 originentry settings objectorigin,其 service worker registrationcontext object,并且如果 tag 非空字符串 的话,其 tagtagnotifications

    3. objects 是一空的 JavaScript 数组。

    4. notifications 中每一个 notification, 按照其创建的顺序,来创建 Notification 对象表示 notification 并且将该对象压入 objects.

    5. objects 处理 promise

  3. 返回 promise

该方法返回零或多个新的 Notification 对象可能表示已然存在的相同底层 Notification 对象的 notification


为给定 notification fire a service worker notification event named e,使用 NotificationEvent 属性初始化为新的 notification 对象表示 notificationNotification 接口来 fire an event named e 的服务线程通知 event

获取 notification 属性值必须返回其所初始化的值。

ServiceWorkerGlobalScope 对象必须作为属性支持下列 event handler (及其相应的 event handler event type) :

事件处理程序 事件处理事件类型
onnotificationclick notificationclick

Acknowledgments

感谢牛人: Aharon (Vladimir) Lanin, Alex Russell, Arkadiusz Michalski, Boris Zbarsky, David Håsäther, Doug Turner, Drew Wilson, Edward O’Connor, Frederick Hirsch, Ian Hickson, Jake Archibald, James Graham, John Mellor, Jon Lee, Jonas Sicking, Michael Cooper, Michael Henretty, Olli Pettay, Peter Beverloo, Reuben Morais, and Simon Pieters for being awesome.

本标准由 Anne van Kesteren (Mozilla, annevk@annevk.nl)编写。 前几版由 John Gregg (Google, johnnyg@google.com)编写。

根据 CC0, 在法律允许的范围内,编辑们放弃所有版权及与之相关或邻接的权利。

Conformance

All diagrams, examples, and notes in this specification are non-normative, as are all sections explicitly marked non-normative. Everything else in this specification is normative.

The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this specification are to be interpreted as described in RFC2119. For readability, these words do not appear in all uppercase letters in this specification. [RFC2119]

Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)

Index

Terms defined by this specification

References

Normative References

[BIDI]
Mark Davis; Aharon Lanin; Andrew Glass. Unicode Bidirectional Algorithm. 5 June 2014. Unicode Standard Annex #9. URL: http://www.unicode.org/reports/tr9/
[DOM]
Anne van Kesteren; Aryeh Gregor; Ms2ger. DOM. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Ian Hickson. HTML. Living Standard. URL: https://html.spec.whatwg.org/
[LANG]
Addison Phillips; Mark Davis. Tags for Identifying Languages; Matching of Language Tags. URL: http://tools.ietf.org/html/bcp47
[URL]
Anne van Kesteren; Sam Ruby. URL. URL: https://url.spec.whatwg.org/
[WEBIDL]
Cameron McCormack; Jonas Sicking. Web IDL. URL: http://heycam.github.io/webidl/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: http://www.ietf.org/rfc/rfc2119.txt
[VIBRATION]
Anssi Kostiainen. Vibration API. 9 September 2014. CR. URL: http://www.w3.org/TR/vibration/

IDL Index

[Constructor(DOMString title, optional NotificationOptions options),
 Exposed=(Window,Worker)]
interface Notification : EventTarget {
  static readonly attribute NotificationPermission permission;
  [Exposed=Window] static void requestPermission(optional NotificationPermissionCallback callback);

  attribute EventHandler onclick;
  attribute EventHandler onerror;

  readonly attribute DOMString title;
  readonly attribute NotificationDirection dir;
  readonly attribute DOMString lang;
  readonly attribute DOMString body;
  readonly attribute DOMString tag;
  readonly attribute USVString icon;
  readonly attribute USVString sound;
  // vibrate not exposed for now; see bug 23682
  readonly attribute boolean renotify;
  readonly attribute boolean silent;
  readonly attribute boolean noscreen;
  readonly attribute boolean sticky;
  [SameObject] readonly attribute any data;

  void close();
};

dictionary NotificationOptions {
  NotificationDirection dir = "auto";
  DOMString lang = "";
  DOMString body = "";
  DOMString tag = "";
  USVString icon;
  USVString sound;
  VibratePattern vibrate;
  boolean renotify = false;
  boolean silent = false;
  boolean noscreen = false;
  boolean sticky = false;
  any data = null;
};

enum NotificationPermission {
  "default",
  "denied",
  "granted"
};

callback NotificationPermissionCallback = void (NotificationPermission permission);

enum NotificationDirection {
  "auto",
  "ltr",
  "rtl"
};

dictionary GetNotificationOptions {
  DOMString tag = "";
};

partial interface ServiceWorkerRegistration {
  Promise<void> showNotification(DOMString title, optional NotificationOptions options);
  Promise<sequence<Notification>> getNotifications(optional GetNotificationOptions filter);
};

[Constructor(DOMString type, optional NotificationEventInit eventInitDict),
 Exposed=ServiceWorker]
interface NotificationEvent : ExtendableEvent {
  readonly attribute Notification notification;
};

dictionary NotificationEventInit : ExtendableEventInit {
  required Notification notification;
};

partial interface ServiceWorkerGlobalScope {
  attribute EventHandler onnotificationclick;
};