Я искал несколько часов, как заставить работать мое настраиваемое push-уведомление.Вот как я настроил свой проект: нет интерфейсной среды, серверной части Node.js / Express.js, Firebase Cloud Messaging (FCM) в качестве менеджера push-уведомлений и сотрудника по обслуживанию.В настоящее время я размещаю приложение на localhost, у меня настроен HTTPS и manifest.json, который содержит минимальное количество полей для начала работы.Манифест.json содержит поле start_url, которое указывает на /index.html, целевую страницу приложения.Приложение поставляется в комплекте с веб-пакетом версии 4.
Back-end
На сервере я установил SDK Firebase Admin в конкретном маршрутизаторе и отправил пользовательский объект уведомлениянемного похоже на следующее для сервера FCM:
let fcMessage = {
data : {
title : 'Foo',
tag : 'url to view that opens bar.html'
}
};
Когда на бэкэнде происходит интересное событие, он получает список пользователей, который содержит маркеры регистрации FCM, и отправляет уведомление на серверы FCM.,Эта часть прекрасно работает.
Front-end
У меня есть двое сервисных работников на front-end.Внутри моего внешнего файла index.js я регистрирую настраиваемого работника службы с именем sw.js в корне домена и приказываю firebase использовать этого работника следующим образом:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js')
.then(registration => {
messaging.useServiceWorker(registration);
})
.catch(err => console.error(`OOps! ${err}`));
}
FCM и его учетные данные настроеныи пользователь может подписаться на push-уведомления.Я не буду показывать этот код здесь, так как он работает, и я не верю, что это проблема.
Теперь перейдем к самим работникам службы.У меня есть файл firebase-messaging-sw.js в корне моего домена.Он содержит следующий код:
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');
firebase.initializeApp(configuration);
const messaging = firebase.messaging();
Конфигурация является просто заполнителем для всех кредитов.Опять же, это работает.
Что я хочу сделать, это НЕ использовать push-уведомление FCM, а вместо этого создать собственное push-уведомление, содержащее URL-адрес для представления, на которое пользователь может щелкнуть и перейти к этому представлению.Следующий код почти работает и является хаком , который я нашел на другом сайте:
class CustomPushEvent extends Event {
constructor(data) {
super('push');
Object.assign(this, data);
this.custom = true;
}
}
self.addEventListener('push', (e) => {
console.log('[Service Worker] heard a push ', e);
// Skip if event is our own custom event
if (e.custom) return;
// Keep old event data to override
let oldData = e.data;
// Create a new event to dispatch
let newEvent = new CustomPushEvent({
data: {
json() {
let newData = oldData.json();
newData._notification = newData.notification;
delete newData.notification;
return newData;
},
},
waitUntil: e.waitUntil.bind(e),
})
// Stop event propagation
e.stopImmediatePropagation();
// Dispatch the new wrapped event
dispatchEvent(newEvent);
});
messaging.setBackgroundMessageHandler(function(payload) {
if (payload.hasOwnProperty('_notification')) {
return self.registration.showNotification(payload.data.title,
{
body : payload.data.text,
actions : [
{
action : `${payload.data.tag}`,
title : 'Go to link'
}
]
});
} else {
return;
}
});
self.addEventListener('notificationclick', function(e) {
console.log('CLICK');
e.notification.close();
e.waitUntil(clients.matchAll({ type : 'window' })
.then(function(clientList) {
console.log('client List ', clientList);
const cLng = clientList.length;
if (clientList.length > 0) {
for (let i = 0; i < cLng; i++) {
const client = clientList[i];
if (client.url === '/' && 'focus' in client) {
return client.focus();
}
}
} else {
console.log('no clients ', e.action);
clients.openWindow(e.action)
.then(client => {
console.log('client ', client);
return client.navigate(e.action);
})
.catch(err => console.error(`[Service Worker] cannot open client : ${err} `));
}
}))
});
Хак предназначен для захвата события push и полезной нагрузки уведомления по умолчанию FCM и вместо этого служит для этой полезной нагрузки.через пользовательский, сделанный через Notification API .
Приведенный выше код прекрасно работает, но ТОЛЬКО если я помещу его в файл firebase-messaging-sw.js.Это не то, что я действительно хочу сделать: я хочу вместо этого поместить его в файл sw.js, но когда я это сделаю, sw.js не может слышать какие-либо push-события, и вместо этого я получаю push-уведомление FCM по умолчанию.Я также попытался импортировать все сценарии Firebase-Messaging-SW в пользовательский сервисный работник, и он по-прежнему не будет слышать события сообщений.
Почему я хочу использовать его в своем сервисном работнике вместоFirebase один?Это должно быть в состоянии открыть приложение в представлении, переданном в поле 'tag' в теле уведомления.Если я использую сервисного работника Firebase, он говорит мне, что он не является активным зарегистрированным сервисным работником, и, хотя приложение открывается в новом окне, оно открывается только в /index.html.
Некоторые незначительные замечания, которые я 've made: массив клиентов всегда пуст, когда последний бит кода добавляется в файл firebase-messaging-sw.js.Пользовательский сервисный работник установлен правильно, потому что он обрабатывает кеш оболочки приложения и нормально прослушивает все остальные события.Работник службы Firebase-Messaging-SW также установлен правильно.