As notificações do iOS podem perder a permissão de push se a notificação for suprimida. O código do Discourse está configurado para suprimir opcionalmente as notificações e, portanto, perderá a permissão de push quando isso acontecer três vezes.
Aqui está o código para o service worker de notificação push.
Este código tem um bug crítico, na linha 178. Lá, o service worker verifica se o usuário está ativo (ou seja, não ocioso). Nesse caso, o evento push retorna false sem mostrar uma notificação.
(Ele também verifica payload.hide_when_active, mas acontece que hide_when_active é sempre verdadeiro, e, portanto, este código sempre retorna false quando o usuário está ativo.)
A Apple proíbe pushes silenciosos, revogando a permissão de push após três eventos que não mostram notificações
Isso não é aceitável de acordo com as regras da Apple para notificações push.
https://webkit.org/blog/12945/meet-web-push/
Poder e privacidade
Tanto o projeto de código aberto WebKit quanto a Apple tratam a privacidade como um direito humano fundamental. Assim como outros recursos privilegiados da plataforma web, solicitar uma assinatura de push requer um gesto explícito do usuário. Também exige que você defina o sinalizador
userVisibleOnlycomotruee cumpra essa promessa mostrando sempre uma notificação em resposta a uma mensagem push.A API Web Push não é um convite para execução em segundo plano silenciosa, pois isso violaria a confiança do usuário e afetaria a vida útil da bateria do usuário.
Violações da promessa
userVisibleOnlyresultarão na revogação de uma assinatura de push.
(ênfase minha)
Isso é explicado em mais detalhes no vídeo WWDC da Apple sobre Web Pushes, em 9:57
https://developer.apple.com/videos/play/wwdc2022/10098/?time=596
Note que estamos declarando explicitamente que prometemos sempre tornar os pushes visíveis para o usuário. Embora o padrão para a API JavaScript Push acomode opcionalmente a execução em segundo plano silenciosa em resposta a um push, a maioria dos navegadores não suporta isso. O Safari não suporta isso.
… e depois em 13:35:
https://developer.apple.com/videos/play/wwdc2022/10098/?time=814
Como mencionado quando mostrei o código sobre como solicitar uma assinatura de push, você deve prometer que os pushes serão visíveis para o usuário. Lidar com um evento de push não é um convite para que seu JavaScript obtenha execução em segundo plano silenciosa. Fazer isso violaria tanto a confiança do usuário quanto a vida útil da bateria do usuário. Ao lidar com um evento de push, você é, na verdade, obrigado a postar uma notificação no Notification Center. Outros navegadores têm contramedidas contra a violação da promessa de tornar os pushes visíveis para o usuário, e o Safari também. Na compilação beta do macOS Ventura, após três eventos de push nos quais você falhar em postar uma notificação em tempo hábil, a assinatura de push do seu site será revogada. Você precisará passar pelo fluxo de permissão novamente.
(ênfase minha)
A Apple recomenda mostrar notificações imediatamente, não após o fechamento de notificações
O código recomendado pela Apple se parece com isto, em 11:39:
https://developer.apple.com/videos/play/wwdc2022/10098/?time=699
self.addEventListener('push', (event) => {
let pushMessageJSON = event.data.json();
// Nosso servidor coloca tudo o que é necessário para mostrar a notificação
// em nossos dados JSON.
event.waitUntil(self.registration.showNotification(pushMessageJSON.title, {
body: pushMessageJSON.body,
tag: pushMessageJSON.tag,
actions: [{
action: pushMessageJSON.actionURL,
title: pushMessageJSON.actionTitle,
}]
}));
}
Lembre-se de que, quando assinamos o push, nosso JavaScript prometeu que eles seriam sempre visíveis para o usuário? Isso significa que devemos sempre mostrar uma notificação nativa da plataforma em resposta a cada push. É melhor fazer isso o mais cedo possível em seu manipulador de eventos push.
O código do Discourse não está seguindo a melhor prática recomendada. O código do Discourse primeiro fecha todas as notificações e só então mostra uma notificação.
O Discourse deve sempre chamar showNotification em resposta a um evento de push, e deve sempre fazê-lo o mais rápido possível.