Реалізація сповіщень із розширення браузера
Розширення браузера можуть показувати системні сповіщення через chrome.notifications API. Це нативні сповіщення ОС, а не спливаючі вікна на сторінці — вони з'являються в системному треї навіть коли браузер згорнутий.
Дозвіл у маніфесті
{
"permissions": ["notifications"]
}
Типи сповіщень
basic — заголовок + текст + іконка. Найпоширеніший тип.
image — з великим зображенням. На macOS не відображається (ігнорується).
list — список елементів. Підтримка залежить від ОС.
progress — прогрес-бар. Корисний для фонових завантажень.
Створення сповіщення
// background/sw.js
async function showNotification(id, options) {
return new Promise((resolve) => {
chrome.notifications.create(id, {
type: 'basic',
iconUrl: chrome.runtime.getURL('icons/icon-128.png'),
title: options.title,
message: options.message,
priority: 1, // 0 = низький, 1 = звичайний, 2 = високий
requireInteraction: options.persistent ?? false, // не ховати автоматично
buttons: options.buttons ?? [],
silent: options.silent ?? false
}, resolve);
});
}
// Використання
await showNotification('sync-complete', {
title: 'Синхронізація завершена',
message: 'Додано 3 нові записи',
buttons: [{ title: 'Відкрити' }]
});
Якщо передати порожній рядок як id — браузер згенерує унікальний id і повернеть його через callback.
Сповіщення з прогресом
async function showProgress(jobId, title, progress) {
const exists = await notificationExists(jobId);
if (!exists) {
chrome.notifications.create(jobId, {
type: 'progress',
iconUrl: chrome.runtime.getURL('icons/icon-128.png'),
title,
message: `${progress}%`,
progress
});
} else {
chrome.notifications.update(jobId, {
progress,
message: `${progress}%`
});
}
}
function notificationExists(id) {
return new Promise((resolve) => {
chrome.notifications.getAll((all) => resolve(id in all));
});
}
// Приклад використання при завантаженні файлу
async function downloadWithProgress(url, filename) {
const jobId = `download-${Date.now()}`;
await showProgress(jobId, `Завантаження: ${filename}`, 0);
const response = await fetch(url);
const total = parseInt(response.headers.get('content-length') ?? '0');
const reader = response.body.getReader();
let received = 0;
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
received += value.length;
if (total > 0) {
await showProgress(jobId, `Завантаження: ${filename}`, Math.round(received / total * 100));
}
}
chrome.notifications.clear(jobId);
return new Blob(chunks);
}
Обробка кліків по сповіщенню
chrome.notifications.onClicked.addListener(async (notificationId) => {
chrome.notifications.clear(notificationId);
// Відкриваємо потрібну вкладку або фокусуємо на існуючій
if (notificationId.startsWith('new-message-')) {
const messageId = notificationId.split('-').at(-1);
await openOrFocusTab(`/messages/${messageId}`);
}
});
chrome.notifications.onButtonClicked.addListener(async (notificationId, buttonIndex) => {
chrome.notifications.clear(notificationId);
if (notificationId === 'sync-complete' && buttonIndex === 0) {
// Кнопка "Відкрити"
await chrome.tabs.create({ url: chrome.runtime.getURL('pages/dashboard.html') });
}
});
async function openOrFocusTab(path) {
const url = chrome.runtime.getURL(`pages/app.html${path}`);
const [existing] = await chrome.tabs.query({ url: `${chrome.runtime.getURL('pages/app.html')}*` });
if (existing) {
await chrome.tabs.update(existing.id, { active: true, url });
await chrome.windows.update(existing.windowId, { focused: true });
} else {
await chrome.tabs.create({ url });
}
}
Сповіщення для періодичних завдань
Типовий паттерн — сповіщення від будильника:
chrome.alarms.onAlarm.addListener(async (alarm) => {
if (alarm.name !== 'check-updates') return;
const updates = await fetchUpdates();
if (updates.length === 0) return;
if (updates.length === 1) {
chrome.notifications.create('update-1', {
type: 'basic',
iconUrl: chrome.runtime.getURL('icons/icon-128.png'),
title: updates[0].title,
message: updates[0].body,
contextMessage: new URL(updates[0].url).hostname
});
} else {
chrome.notifications.create('updates-batch', {
type: 'list',
iconUrl: chrome.runtime.getURL('icons/icon-128.png'),
title: `${updates.length} нових оновлень`,
message: '',
items: updates.slice(0, 8).map(u => ({
title: u.title,
message: new URL(u.url).hostname
}))
});
}
});
На Windows сповіщення потрапляють до центру сповіщень. На macOS — до Notification Center. На Linux — через libnotify, зовнішній вигляд залежить від DE. Врахуйте це при тестуванні: на macOS тип list і image не відображають додатковий контент.







