跳转到内容

通知的 actions 与 badge 选项

发布于 更新于

一句话: actions 最多可以为一条通知添加 Notification.maxActions 个可点击按钮;badge 是一个独立的选项——根据 MDN,它是操作系统在 “there is not enough space to display the notification itself”(没有足够空间展示完整通知)时展示的一张小图片,例如 Android 的通知栏。 这两者都是 Service Worker 驱动通知上的选项,并不是应用图标的 Badging API。

  • actions —— 根据 MDN,这是一个只读数组,其元素为对象,包含 action(标识字符串)、 title(按钮文案)、可选的 icon URL,以及可选的 navigate URL。根据 MDN,“browsers typically limit the maximum number of actions they will display”(浏览器通常会限制展示的 按钮数量),该上限通过静态属性 Notification.maxActions 暴露。
  • badge —— 根据 MDN,它是 “a string containing the URL of an image”(一个包含图片 URL 的字符串),在空间不足时替代完整通知展示;MDN 针对 Android 的指引建议尺寸 “about 96 by 96 px”(约 96×96 像素),并说明该图片 “will be automatically masked”(会被自动进行遮罩处理)。
const permission = await Notification.requestPermission();
if (permission === 'granted') {
const registration = await navigator.serviceWorker.ready;
await registration.showNotification('New message', {
body: 'Ada sent you a message.',
badge: '/icons/badge-96.png',
actions: [
{ action: 'reply', title: 'Reply' },
{ action: 'dismiss', title: 'Dismiss' },
],
});
}

根据 MDN,actions 仅 “only for persistent notifications”(适用于持久化通知)——即通过 ServiceWorkerRegistration.showNotification() 展示的通知——而不适用于直接 new Notification()。MDN 指出,向 Notification() 构造函数传入非 null 的 actions 选项会 “throws a TypeError”(抛出 TypeError)。

点击某个操作按钮后会发生什么,取决于该 action 是否设置了 navigate URL。根据 MDN 的 actions 文档,如果设置了 navigate,浏览器会直接导航到该 URL,并且不会派发 notificationclick 事件。只有当某个 action 没有设置 navigate URL 时,点击才会到达 Service Worker 的 notificationclick 事件,此时 event.action 中保存着被点击按钮的 action 字符串。

根据上面引用的 browser-compat-data:

浏览器 actions badge
Chrome(桌面版) 支持,自 53 版起 支持,自 53 版起
Edge(桌面版) 支持,自 18 版起 支持,自 18 版起
Opera(桌面版) 支持,自 39 版起 支持,自 39 版起
Firefox(桌面版) 支持,自 152 版起 不支持
Safari 不支持 不支持

根据 MDN,这两个选项都要求安全上下文。

function canShowActionsAndBadge() {
if (!('serviceWorker' in navigator) || !('Notification' in window)) {
return { actions: false, badge: false }; // 这里完全不具备持久化通知能力
}
return {
actions: 'actions' in Notification.prototype,
badge: 'badge' in Notification.prototype,
};
}
async function notifyNewMessage(registration) {
const { actions, badge } = canShowActionsAndBadge();
const options = { body: 'Ada sent you a message.' };
if (badge) {
options.badge = '/icons/badge-96.png';
}
if (actions) {
options.actions = [
{ action: 'reply', title: 'Reply' },
{ action: 'dismiss', title: 'Dismiss' },
];
}
// 当不支持 actions/badge 时,这里会改为发送仅含正文的通知——上面这些选项
// 只是被省略,而不会导致报错。
await registration.showNotification('New message', options);
}
  • 不要向 new Notification() 传入 actions 选项——根据 MDN,在非持久化(非 Service Worker)通知上这样做会抛出 TypeError。
  • 使用 Notification.maxActions 而不是硬编码按钮数量;不同浏览器的上限不同。
  • 不要把 badge 选项的小型通知栏图片与独立的应用图标 Badging API (navigator.setAppBadge()) 混淆——它们解决的是不同的问题。
  • 对设置了 navigate URL 的 action,预期浏览器会直接导航,而不会触发 notificationclick 事件;只有未设置 navigate 的 action 才会到达 Service Worker 的 notificationclick 事件,此时才在其中读取 event.action。
  • 依赖 actions 前先确认上方的支持情况表——尤其是 Firefox;两个选项在 Safari 上都不 受支持。
  • Notifications API —— 这两个选项所依赖的 基础权限模型与“页面 vs Service Worker”区分。
  • 应用图标徽章 —— 用于在已安装应用图标上设置数字的 独立 Badging API。