首页 / 浏览器扩展开发入门教程 / 通知 notifications

浏览器扩展开发入门教程

通知 notifications

本教程共 56 篇 · 第 31 篇 · 更新于 2026-08-13 · 约 7 分钟阅读

notifications通知系统通知用户界面Manifest V3事件回调

本节目标:学完你能用 chrome.notifications 弹出系统级通知,会选四种模板、配好图标和按钮,并能接住用户点击通知或按钮后的回调。

前面几章讲的界面组件都在浏览器里面:popup、侧边栏、右键菜单。但有些消息不能等用户回到浏览器才看到——下载完成了、定时提醒到了、后台任务出错了。这时候需要跳出浏览器,用操作系统的通知中心弹一条。

这就是 chrome.notifications 干的事。它不是网页里那种自绘的浮层,而是真正交给 Windows 通知中心、macOS 通知栏去显示的系统通知。

31-1 通知长什么样、什么脾气

一条通知通常包含四块:小图标、标题、正文、可选的按钮。系统会把它显示在屏幕角落,几秒后自动收进通知中心。

它的行为有几个特点你要提前知道,不然会觉得”我的通知怎么没了”:

  • 它会自己消失。桌面上停留几秒就淡出,但仍留在系统通知中心里,用户可以回看。
  • 它归系统管。用户在操作系统层面把 Chrome 的通知权限关了,你怎么调 API 都不会显示。
  • 样式不能自定义。你只能选模板、填内容,具体长什么样由操作系统决定。
  • 平台有差异。同一段代码在 Windows 和 macOS 上显示效果会略有不同。
Note

通知是”打扰型”界面。用得好是贴心提醒,用滥了就是骚扰,用户会直接卸载。只在真正需要用户立刻知道的时候发。

31-2 先声明 notifications 权限

chrome.notifications 需要权限,清单里写上:

{
  "manifest_version": 3,
  "name": "通知示例",
  "version": "1.0.0",
  "permissions": ["notifications"],
  "background": {
    "service_worker": "service-worker.js"
  },
  "action": {
    "default_popup": "popup.html"
  },
  "icons": {
    "16": "images/icon-16.png",
    "48": "images/icon-48.png",
    "128": "images/icon-128.png"
  }
}

"notifications" 属于普通权限,不需要宿主权限,安装时用户会看到”显示通知”这条提示。

31-3 notifications.create 的最小写法

创建通知只有一个入口:chrome.notifications.create()

await chrome.notifications.create(id, options);
  • id:可选,通知的唯一标识。传了它,之后就能用同一个 id 去更新或清除这条通知。不传,浏览器自动生成一个,通过回调或返回值拿到。
  • options:通知内容对象,typetitlemessageiconUrl 是最基础的四项。

最常用的 basic 模板:

const options = {
  type: 'basic',
  iconUrl: 'images/icon-128.png',
  title: '下载完成',
  message: '报表已保存到下载目录。'
};

chrome.notifications.create('download-done', options);

这四个字段里,typetitlemessageiconUrl 在创建时都是必填的。少一个就会报错,这是新手最常见的失败原因。

Tip

通知代码最适合放在服务工作者(Service Worker)里。因为触发通知的往往是后台事件:定时器到点、下载结束、网络请求返回。popup 里也能调,但 popup 一关脚本就停了,不适合承载后台逻辑。

31-4 四种模板逐个看

type 字段决定通知的版式,一共四种。

basic:纯文字

最常规的一条,图标加标题加正文。

const options = {
  type: 'basic',
  title: 'Primary Title',
  message: 'Primary message to display',
  iconUrl: 'images/icon-128.png'
};

image:带预览图

在正文下面多一张大图,适合截图完成、图片处理完成这类场景。

const options = {
  type: 'image',
  title: '截图已保存',
  message: '点击查看完整图片。',
  iconUrl: 'images/icon-128.png',
  imageUrl: 'images/preview.png'
};

imageUrl 是预览大图,iconUrl 仍然是左侧小图标,两者别搞混。

list:条目列表

一次要报多条内容时用它,比如”有 3 封新邮件”。

const options = {
  type: 'list',
  title: '你有 3 条新消息',
  message: '点击查看全部',
  iconUrl: 'images/icon-128.png',
  items: [
    { title: 'Item1', message: 'This is item 1.' },
    { title: 'Item2', message: 'This is item 2.' },
    { title: 'Item3', message: 'This is item 3.' }
  ]
};

items 是数组,每项有自己的 titlemessage

progress:进度条

progress 模板会显示一条进度条,取值范围是 0 到 100。

const options = {
  type: 'progress',
  title: '正在同步',
  message: '已完成 42%',
  iconUrl: 'images/icon-128.png',
  progress: 42
};
Note

平台差异在这里最明显:据社区经验,在 macOS 上进度可能不画成进度条,而是以百分比数值显示在通知标题里(此行为未见于官方文档,建议实测)。另外 imageUrl 字段自 Chrome 59 起已被标记 deprecated,且在 Mac 上不可见,跨平台使用时别依赖它。

31-5 iconUrl 图标怎么给

iconUrl 是最容易出错的字段,三条规则就够:

  1. 必须是扩展包内的相对路径,比如 'images/icon-128.png'。写成外链远程图片在 Manifest V3 下不可靠。
  2. 尺寸给大一点。建议直接复用 128×128 的那张图标,系统会自己缩放。给 16×16 的小图在高分屏上会糊。
  3. 路径写错不会静默失败create() 会抛错。调试时先去服务工作者的控制台看有没有报错。

需要绝对地址时可以用 chrome.runtime.getURL()

const options = {
  type: 'basic',
  iconUrl: chrome.runtime.getURL('images/icon-128.png'),
  title: '提醒',
  message: '喝水时间到了。'
};

chrome.notifications.create(options);

注意这次没传 id,只传了 options,这也是合法调用。

31-6 加按钮,接回调

通知可以带最多两个按钮,让用户直接在通知上做动作,不用回到浏览器。

chrome.notifications.create('water-reminder', {
  type: 'basic',
  iconUrl: 'images/icon-128.png',
  title: '喝水提醒',
  message: '已经一小时没喝水了。',
  buttons: [{ title: '我喝了' }, { title: '稍后提醒' }]
});

按钮点了要有反应,就得监听事件。通知相关有三个常用事件:

// 用户点击了通知主体
chrome.notifications.onClicked.addListener((notificationId) => {
  chrome.tabs.create({ url: 'https://example.com/detail' });
  chrome.notifications.clear(notificationId);
});

// 用户点击了通知上的按钮
chrome.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => {
  if (buttonIndex === 0) {
    console.log('用户点了「我喝了」');
  } else {
    console.log('用户点了「稍后提醒」');
  }
  chrome.notifications.clear(notificationId);
});

// 通知被关闭(自动消失或用户手动关)
chrome.notifications.onClosed.addListener((notificationId, byUser) => {
  console.log(notificationId, byUser ? '被用户关掉了' : '自动消失了');
});

buttonIndex 就是 buttons 数组的下标,第一个按钮是 0,第二个是 1。

除了按钮,options 里还有几个字段值得知道:

  • priority:优先级,取值 -2 到 2,数字越大越显眼、停留越久。默认 0 就够用,别一律拉满。
  • requireInteraction:设为 true 时通知不自动消失,要等用户自己处理。只留给真正重要的事,比如任务失败需要确认。
  • silent:设为 true 就静音弹出,不发提示音。高频低价值的通知建议开静音。
  • contextMessage:一行灰色的补充说明,适合放来源或时间戳。
chrome.notifications.create('sync-failed', {
  type: 'basic',
  iconUrl: 'images/icon-128.png',
  title: '同步失败',
  message: '服务器没有响应,请稍后重试。',
  contextMessage: '来自「我的同步工具」',
  priority: 2,
  requireInteraction: true
});
Warning

事件监听器必须写在服务工作者的顶层,不能塞在某个函数里等以后再注册。后台是事件驱动、随时休眠的,只有顶层注册的监听器才能在休眠后被事件重新唤醒。这条规则在服务工作者那章讲过,通知这里同样适用。

31-7 更新、清除与查询

传了 id 的通知可以后续操作,这也是”传 id”最大的价值。

同步进度就是典型场景——不要每次都创建新通知,而是更新同一条:

const NOTIF_ID = 'sync-progress';

async function reportProgress(percent) {
  await chrome.notifications.update(NOTIF_ID, {
    progress: percent,
    message: `已完成 ${percent}%`
  });
}

任务结束后主动清掉:

await chrome.notifications.clear(NOTIF_ID);

想知道当前还有哪些通知在,用 getAll()

const all = await chrome.notifications.getAll();
console.log(Object.keys(all)); // 所有还活着的通知 id

getAll() 返回的是一个对象,key 是通知 id,不是数组,别直接当数组遍历。

31-8 小结与实践建议

回顾这一节的骨架:清单加 "notifications" 权限 → chrome.notifications.create(id, options) 填四件套(type / title / message / iconUrl)→ 按需选模板(basic / image / list / progress)→ 顶层注册 onClickedonButtonClickedonClosed 接住交互 → 用 id 做 update / clear / getAll

再给三条实践建议。第一,重要通知带上按钮,让用户一步完成操作,别逼他打开浏览器再找入口。第二,同一件事复用同一个 id,避免通知刷屏。第三,做好”通知被系统屏蔽”的兜底,重要状态在 popup 或侧边栏里也要能看到。

下一节换个方向,我们讲 devtools 面板扩展——怎么给浏览器的开发者工具加一个属于你自己的标签页。