iOS의 경우, 알림이 억제(suppressed)되면 푸시 권한을 잃을 수 있습니다. Discourse의 코드는 알림을 선택적으로 억제하도록 구성되어 있으며, 이 상황이 세 번 발생하면 푸시 권한이 취소됩니다.
다음은 푸시 알림 서비스 워커의 코드입니다.
이 코드에는 178번째 줄에 치명적인 버그가 있습니다. 해당 부분에서 서비스 워커는 사용자가 활성 상태(즉, 유휴 상태가 아님)인지 확인합니다. 사용자가 활성 상태인 경우, 알림을 표시하지 않고 푸시 이벤트가 false를 반환합니다.
(또한 payload.hide_when_active를 확인하지만, hide_when_active는 항상 true인 것으로 밝혀졌으며, 따라서 사용자가 활성 상태일 때 이 코드는 항상 false를 반환합니다.)
Apple은 조용한 푸시를 금지하며, 알림을 표시하지 않는 이벤트가 3회 발생하면 푸시 권한을 취소합니다
이는 Apple의 푸시 알림 규칙에 따라 허용되지 않습니다.
https://webkit.org/blog/12945/meet-web-push/
전력 및 프라이버시
WebKit 오픈소스 프로젝트와 Apple 모두 프라이버시를 근본적인 인권으로 간주합니다. 웹 플랫폼의 다른 특권 기능이 그렇듯이, 푸시 구독을 요청하려면 명시적인 사용자 제스처가 필요합니다. 또한
userVisibleOnly플래그를 true로 설정하고, 푸시 메시지에 대한 응답으로 항상 알림을 표시하여 이 약속을 이행해야 합니다.Web Push API는 조용한 백그라운드 런타임(silent background runtime)을 위한 초대가 아닙니다. 그렇게 하면 사용자의 신뢰를 위반할 뿐만 아니라 배터리 수명에 영향을 미치기 때문입니다.
userVisibleOnly약속을 위반하면 푸시 구독이 취소됩니다.
(강조는 저의 것입니다)
이 내용은 Apple의 Web Push에 관한 WWDC 비디오의 9:57 지점에서 더 자세히 설명되어 있습니다.
https://developer.apple.com/videos/play/wwdc2022/10098/?time=596
푸시에 대해 항상 사용자 가시적으로(user visible) 만들겠다고 명시적으로 약속하고 있다는 점에 유의하십시오. JavaScript Push API 표준은 푸시에 대한 응답으로 조용한 JavaScript 런타임을 선택적으로 수용하지만, 대부분의 브라우저는 이를 지원하지 않습니다. Safari도 이를 지원하지 않습니다.
… 그리고 13:35 지점에서는 다음과 같이 설명합니다:
https://developer.apple.com/videos/play/wwdc2022/10098/?time=814
푸시 구독을 요청하는 방법을 보여준 코드에서 언급했듯이, 푸시가 사용자 가시적일 것임을 약속해야 합니다. 푸시 이벤트를 처리하는 것은 JavaScript가 조용한 백그라운드 런타임을 얻기 위한 초대가 아닙니다. 그렇게 하면 사용자의 신뢰와 배터리 수리에 모두 해를 끼치기 때문입니다. 푸시 이벤트를 처리할 때는 사실 Notification Center에 알림을 게시하는 것이 요구됩니다. 다른 브라우저들은 모두 푸시가 사용자 가시적이라는 약속을 위반하는 것에 대한 대응 조치를 갖추고 있으며, Safari도 마찬가지입니다. macOS Ventura의 베타 빌드에서, 적시에 알림을 게시하지 못하는 푸시 이벤트가 3회 발생하면 해당 사이트의 푸시 구독이 취소됩니다. 다시 권한 워크플로우를 거쳐야 합니다.
(강조는 저의 것입니다)
Apple은 알림을 닫은 후가 아니라 즉시 표시할 것을 권장합니다
Apple이 권장하는 코드는 11:39 지점의 다음과 같습니다:
https://developer.apple.com/videos/play/wwdc2022/10098/?time=699
self.addEventListener('push', (event) => {
let pushMessageJSON = event.data.json();
// Our server puts everything needed to show the notification
// in our JSON data.
event.waitUntil(self.registration.showNotification(pushMessageJSON.title, {
body: pushMessageJSON.body,
tag: pushMessageJSON.tag,
actions: [{
action: pushMessageJSON.actionURL,
title: pushMessageJSON.actionTitle,
}]
}));
}
푸시를 구독할 때 JavaScript가 항상 사용자 가시적일 것임을 약속했다는 점을 기억하십시오. 즉, 각 푸시에 대한 응답으로 플랫폼 네이티브 알림을 항상 표시해야 합니다. 이는 푸시 이벤트 핸들러에서 가능한 한 초기에 수행하는 것이 가장 좋습니다.
Discourse의 코드는 권장되는 모범 사례를 따르지 않습니다. Discourse의 코드는 먼저 모든 알림을 닫은 다음, 비로소 알림을 표시합니다.
Discourse는 푸시 이벤트에 대한 응답으로 항상 showNotification을 호출해야 하며, 항상 가능한 한 빨리 이를 수행해야 합니다.