Assinatura de notificação push em PWA do iOS falha silenciosamente devido ao SW não controlar o aplicativo

Olá :waving_hand:

Encontramos um comportamento estranho (ou provavelmente um bug…) ao configurar notificações push no PWA para iOS. A interface age como se a assinatura de notificações push tivesse sido configurada, enquanto, em segundo plano, nada aconteceu ainda e o usuário nunca receberá nenhuma notificação push.

(tl;dr: Acredito que sei como corrigir isso e posso fornecer um PR)

Passos para reproduzir :footprints:

O problema ocorre ao ativar notificações push imediatamente após instalar o PWA no iOS.

  1. Abra sua instância do Discourse no Safari móvel no iOS
  2. Abra o menu de compartilhamento e escolha “Adicionar à tela inicial”
  3. Abra o novo PWA na sua tela inicial
  4. Você verá um banner perguntando se deseja ativar notificações push
  5. Clique no link “ativar notificações”
    1. Você verá um diálogo do sistema: “xyz” gostaria de enviar notificações para você - aceite.
  6. Ao navegar para suas preferências de notificação, você verá que notificações em tempo real não estão ativadas.
    1. Verificando no servidor, também não encontrará um novo registro PushSubscription para o usuário.

Comportamento esperado :books:

Após o passo 5, você já deveria receber uma notificação push informando que as notificações foram ativadas. Também deve haver um novo registro PushSubscription para seu usuário atual no banco de dados, e sua configuração para receber notificações em tempo real no PWA deve estar ativada.

Problema :bug:

Em um PWA recém-iniciado, o service worker foi instalado e ativado, mas ainda não controla a página. Com isso, a verificação em lib/push-notifications.js, isPushNotificationsSupported(), ainda retornará false, pois navigator.serviceWorker.controller retorna null. Estas são as duas linhas importantes:

navigator.serviceWorker.controller &&
navigator.serviceWorker.controller.state === "activated"

Com isso, a interface sugere ao usuário que tudo está correto com a configuração, mas eles nunca receberão nenhuma notificação push.

Na primeira carga, o PWA está sem controle e a chamada a subscribe() nunca é feita, mesmo que o usuário tenha concedido permissão… :bug:

Os usuários podem corrigir o problema por conta própria, se souberem como:

  1. Fechar completamente o PWA (deslize para longe…)
  2. Abrir o PWA novamente
  3. Acessar suas preferências de notificação
  4. Ativar notificações em tempo real novamente
  5. -> Desta vez, deve haver um novo registro PushSubscription e as notificações estarão configuradas.

Correção Potencial :adhesive_bandage:

Contornei esse problema registrando outro service worker que chama skipWaiting() e clients.claim() durante a instalação/ativação. Ao fazer isso, ele assume imediatamente o controle sobre o PWA, a assinatura é concluída e o respectivo registro PushSubscription é criado.

Implementei isso como uma “correção rápida” como parte de um dos meus plugins personalizados, para que pudesse corrigir a situação para meus usuários sem precisar fazer um fork do núcleo do Discourse…

São apenas duas alterações:

# plugin.rb
register_service_worker "push-notification-setup.js"
// assets/push-notification-setup.js
self.addEventListener("install", function () {
  self.skipWaiting();
});
		
		
self.addEventListener("activate", function (event) {	
  event.waitUntil(self.clients.claim());
});

Acredito que essa correção pertence ao núcleo do Discourse. Com o que estou fazendo, o plugin assume um controle desnecessário sobre o PWA. Posso fornecer um PR que ajuste as verificações no núcleo do Discourse para que a assinatura funcione de verdade. Gostaria de ouvir suas opiniões sobre o assunto aqui, mas fique à vontade para expressar suas opiniões a qualquer momento.

1 curtida

Este é o PR com uma correção para o núcleo do Discourse → FIX: Allow push notification subscriptions on first launch of iOS PWA · Pull Request #39885 · discourse/discourse

Ele resolve o problema descrito aqui, onde a assinatura falha silenciosamente e não chega ao servidor. Mas o que ainda falta, para garantir total segurança, é que a primeira notificação push recebida não será roteável dentro do aplicativo sem que o service worker esteja controlando o app, ou seja, sem que o usuário reinicie o aplicativo.

Isso é algo que eu também poderia adicionar em cima do meu PR. Mas não tenho 100% de certeza se a correção é o que se deseja.

1 curtida