Уведомления на iOS могут потерять разрешение на отправку, если уведомление будет подавлено. Код Discourse настроен на выборочное подавление уведомлений, и в результате потеряет разрешение на отправку, если это произойдет три раза.
Вот код сервис-воркера для push-уведомлений.
В этом коде есть критическая ошибка на строке 178. Там сервис-воркер проверяет, активен ли пользователь (то есть не находится ли он в режиме бездействия). В этом случае событие push возвращает false без отображения уведомления.
(Также проверяется payload.hide_when_active, но оказывается, что hide_when_active всегда true, поэтому этот код всегда возвращает false, когда пользователь активен.)
Apple запрещает тихие push-уведомления и отзывает разрешение на push после трех событий, не приводящих к отображению уведомлений
Это недопустимо согласно правилам Apple для push-уведомлений.
https://webkit.org/blog/12945/meet-web-push/
Мощность и конфиденциальность
И проект с открытым исходным кодом WebKit, и Apple рассматривают конфиденциальность как фундаментальное право человека. Как и в случае с другими привилегированными функциями веб-платформы, запрос подписки на push-уведомления требует явного жеста пользователя. Также требуется установить флаг
userVisibleOnlyв true и выполнить это обещание, всегда показывая уведомление в ответ на push-сообщение.Web Push API не является приглашением к тихому фоновому выполнению, так как это нарушило бы доверие пользователя и повлияло бы на время работы батареи.
Нарушения обещания
userVisibleOnlyприведут к отзыву подписки на push-уведомления.
(выделение мое)
Это подробнее объясняется в видео Apple WWDC о веб-push-уведомлениях, в моменте 9:57
https://developer.apple.com/videos/play/wwdc2022/10098/?time=596
Обратите внимание, что мы явно заявляем, что обещаем всегда делать push-уведомления видимыми для пользователя. Хотя стандарт JavaScript Push API опционально допускает тихое выполнение JavaScript в ответ на push, большинство браузеров этого не поддерживают. Safari не поддерживает этого.
… а затем в 13:35:
https://developer.apple.com/videos/play/wwdc2022/10098/?time=814
Как я упоминал, показывая код запроса подписки на push-уведомления, вы должны обещать, что push-уведомления будут видимы для пользователя. Обработка события push не является приглашением к тихому фоновому выполнению вашего JavaScript. Это нарушило бы как доверие пользователя, так и время работы его батареи. При обработке события push вы фактически обязаны отправить уведомление в Центр уведомлений. Другие браузеры имеют меры противодействия нарушению обещания о видимости push-уведомлений для пользователя, и Safari не является исключением. В бета-версии macOS Ventura после трех событий push, в которых вы не отправите уведомление своевременно, подписка вашего сайта на push-уведомления будет отозвана. Вам придется снова пройти процесс запроса разрешений.
(выделение мое)
Apple рекомендует показывать уведомления немедленно, а не после закрытия уведомлений
Рекомендуемый Apple код выглядит следующим образом, в моменте 11:39:
https://developer.apple.com/videos/play/wwdc2022/10098/?time=699
self.addEventListener('push', (event) => {
let pushMessageJSON = event.data.json();
// Наш сервер помещает все необходимое для отображения уведомления
// в наши JSON-данные.
event.waitUntil(self.registration.showNotification(pushMessageJSON.title, {
body: pushMessageJSON.body,
tag: pushMessageJSON.tag,
actions: [{
action: pushMessageJSON.actionURL,
title: pushMessageJSON.actionTitle,
}]
}));
}
Помните, как при подписке на push наш JavaScript обещал, что они всегда будут видимы для пользователя? Это означает, что мы должны всегда показывать нативное уведомление платформы в ответ на каждый push. Лучше всего делать это как можно раньше в обработчике события push.
Код Discourse не следует рекомендуемой лучшей практике. Код Discourse сначала закрывает все уведомления, и только затем показывает уведомление.
Discourse всегда должен вызывать showNotification в ответ на событие push, и делать это как можно скорее.