Esamineremo alcuni pattern di implementazione comuni per il push web.
Sarà necessario utilizzare alcune API diverse disponibili nel service worker.
Evento di chiusura notifica
Nell'ultima sezione abbiamo visto come ascoltare gli eventi notificationclick
.
Esiste anche un evento notificationclose
che viene chiamato se l'utente ignora uno dei tuoi
(ovvero, invece di fare clic sulla notifica, l'utente fa clic sulla croce o scorre
notifica).
Normalmente questo evento viene utilizzato per dati e analisi al fine di monitorare il coinvolgimento degli utenti con le notifiche.
self.addEventListener('notificationclose', function (event) {
const dismissedNotification = event.notification;
const promiseChain = notificationCloseAnalytics();
event.waitUntil(promiseChain);
});
Aggiunta di dati a una notifica
Quando un messaggio push viene ricevuto, è normale che i dati siano utile se l'utente ha fatto clic sulla notifica. Ad esempio, l'URL che dovrebbe essere aperto quando si fa clic su una notifica.
Il modo più semplice per acquisire i dati da un evento push e collegarli a un
la notifica consiste nell'aggiungere un parametro data
all'oggetto opzioni passato
in showNotification()
, in questo modo:
const options = {
body:
'This notification has data attached to it that is printed ' +
"to the console when it's clicked.",
tag: 'data-notification',
data: {
time: new Date(Date.now()).toString(),
message: 'Hello, World!',
},
};
registration.showNotification('Notification with Data', options);
All'interno di un gestore dei clic, è possibile accedere ai dati con event.notification.data
.
const notificationData = event.notification.data;
console.log('');
console.log('The notification data has the following parameters:');
Object.keys(notificationData).forEach((key) => {
console.log(` ${key}: ${notificationData[key]}`);
});
console.log('');
Aprire una finestra
Una delle risposte più comuni a una notifica è aprire un
finestra / scheda a un URL specifico. Possiamo farlo con
clients.openWindow()
tramite Google Cloud CLI
o tramite l'API Compute Engine.
Nel nostro evento notificationclick
, eseguiremo del codice come questo:
const examplePage = '/demos/notification-examples/example-page.html';
const promiseChain = clients.openWindow(examplePage);
event.waitUntil(promiseChain);
Nella sezione successiva, vedremo come verificare se la pagina a cui vogliamo indirizzare l'utente sia è già aperto o meno. In questo modo, possiamo impostare lo stato attivo sulla scheda aperta invece di aprirne una nuova schede.
Imposta lo stato attivo su una finestra esistente
Quando è possibile, è consigliabile concentrare l'attenzione su una finestra piuttosto che aprirne una nuova ogni volta che l'utente fa clic su una notifica.
Prima di vedere come ottenere questo risultato, vale la pena sottolineare che è possibile solo per le pagine sulla tua origine. Questo perché possiamo vedere solo quali pagine sono aperte e appartengono al nostro sito. In questo modo agli sviluppatori di vedere tutti i siti visitati dai loro utenti.
Riprendendo l'esempio precedente, modificheremo il codice per vedere
/demos/notification-examples/example-page.html
è già aperto.
const urlToOpen = new URL(examplePage, self.location.origin).href;
const promiseChain = clients
.matchAll({
type: 'window',
includeUncontrolled: true,
})
.then((windowClients) => {
let matchingClient = null;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.url === urlToOpen) {
matchingClient = windowClient;
break;
}
}
if (matchingClient) {
return matchingClient.focus();
} else {
return clients.openWindow(urlToOpen);
}
});
event.waitUntil(promiseChain);
Esaminiamo il codice.
Innanzitutto, analizziamo la pagina di esempio utilizzando l'API URL. È un bel trucco che ho preso da Jeff
Posnick. La chiamata a new URL()
con l'oggetto location
restituiscono un URL assoluto se la stringa passata è relativa (ad esempio, /
diventerà
https://example.com/
).
Rendiamo l'URL assoluto in modo da poterlo confrontare in un secondo momento con l'URL della finestra.
const urlToOpen = new URL(examplePage, self.location.origin).href;
Quindi si ottiene un elenco degli oggetti WindowClient
, ovvero l'elenco
schede e finestre attualmente aperte. Ricorda che queste sono schede solo per la tua origine.
const promiseChain = clients.matchAll({
type: 'window',
includeUncontrolled: true,
});
Le opzioni trasmesse a matchAll
comunicano al browser che vogliamo solo
per cercare "finestra" client di tipo (ad es. cerca schede e finestre
ed escludono i web worker). includeUncontrolled
ci consente di cercare
tutte le schede della tua origine che non sono controllate dal servizio attuale
ovvero il service worker che esegue questo codice. In genere,
vuoi sempre che il valore includeUncontrolled
sia impostato su true quando chiami matchAll()
.
Conquistiamo la promessa restituita come promiseChain
in modo da poterla trasmettere
event.waitUntil()
in seguito, mantenendo attivo il nostro service worker.
Una volta risolta la promessa matchAll()
, eseguiamo l'iterazione tramite i client finestra restituiti e
confrontare i loro URL con l'URL che vogliamo aprire. Se troviamo una corrispondenza, concentriamo
per attirare l'attenzione degli utenti. La messa a fuoco si ottiene
Chiamata matchingClient.focus()
.
Se non riusciamo a trovare un cliente corrispondente, apriamo una nuova finestra, come nella sezione precedente.
.then((windowClients) => {
let matchingClient = null;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.url === urlToOpen) {
matchingClient = windowClient;
break;
}
}
if (matchingClient) {
return matchingClient.focus();
} else {
return clients.openWindow(urlToOpen);
}
});
Unione delle notifiche
Abbiamo notato che l'aggiunta di un tag a una notifica comporta l'attivazione di un comportamento che prevede la notifica esistente con lo stesso tag viene sostituita.
Puoi tuttavia diventare più sofisticato con la compressione delle notifiche utilizzando il API Notifications. Prendi in considerazione un'app di chat per la quale lo sviluppatore potrebbe voler ricevere una nuova notifica mostra un messaggio simile a "Hai due messaggi da Matt" anziché mostrare solo le informazioni .
Puoi farlo o manipolare le notifiche correnti in altri modi, utilizzando la registration.getNotifications() API che ti permette di accedere a tutte le notifiche attualmente visibili per la tua applicazione web.
Vediamo come potremmo utilizzare questa API per implementare l'esempio della chat.
Nell'app di chat, supponiamo che ogni notifica contenga dati che includono un nome utente.
La prima cosa da fare è trovare tutte le notifiche aperte per un utente con un
nome utente. Provvederemo a controllare registration.getNotifications()
e a controllare
notification.data
per un nome utente specifico:
const promiseChain = registration.getNotifications().then((notifications) => {
let currentNotification;
for (let i = 0; i < notifications.length; i++) {
if (notifications[i].data && notifications[i].data.userName === userName) {
currentNotification = notifications[i];
}
}
return currentNotification;
});
Il passaggio successivo consiste nel sostituire questa notifica con una nuova.
In questa falsa app di messaggi, terremo traccia del numero di nuovi messaggi aggiungendo un conteggio alla nuova i dati della notifica e lo incrementano a ogni nuova notifica.
.then((currentNotification) => {
let notificationTitle;
const options = {
icon: userIcon,
}
if (currentNotification) {
// We have an open notification, let's do something with it.
const messageCount = currentNotification.data.newMessageCount + 1;
options.body = `You have ${messageCount} new messages from ${userName}.`;
options.data = {
userName: userName,
newMessageCount: messageCount
};
notificationTitle = `New Messages from ${userName}`;
// Remember to close the old notification.
currentNotification.close();
} else {
options.body = `"${userMessage}"`;
options.data = {
userName: userName,
newMessageCount: 1
};
notificationTitle = `New Message from ${userName}`;
}
return registration.showNotification(
notificationTitle,
options
);
});
Se al momento è visualizzata una notifica, aumenteremo il conteggio dei messaggi e impostiamo il valore
titolo della notifica e corpo del messaggio di conseguenza. Se ci sono
non sono presenti notifiche, viene creata una nuova notifica con newMessageCount
pari a 1.
Il risultato è che il primo messaggio avrà il seguente aspetto:
Una seconda notifica comprimeva le notifiche in questa:
L'aspetto positivo di questo approccio è che se l'utente rileva le notifiche che appaiono una sopra l'altra, sembreranno più coerenti che sostituisca la notifica con il messaggio più recente.
L'eccezione alla regola
Ti dico che devi mostrare una notifica quando ricevi un push, che è true nella maggior parte delle volte. L'unico scenario in cui non devi mostrare una notifica è quando l'utente abbia il tuo sito aperto e mirato.
All'interno dell'evento push, puoi verificare se devi mostrare o meno una notifica. esaminare i client della finestra e cercare una finestra con lo stato attivo.
Il codice per recuperare tutte le finestre e cercarne una con lo stato attivo è simile al seguente:
function isClientFocused() {
return clients
.matchAll({
type: 'window',
includeUncontrolled: true,
})
.then((windowClients) => {
let clientIsFocused = false;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.focused) {
clientIsFocused = true;
break;
}
}
return clientIsFocused;
});
}
Usiamo clients.matchAll()
per ottenere tutti i client finestra e poi li controlliamo controllando il parametro focused
.
All'interno dell'evento push, utilizziamo questa funzione per decidere se dobbiamo mostrare una notifica:
const promiseChain = isClientFocused().then((clientIsFocused) => {
if (clientIsFocused) {
console.log("Don't need to show a notification.");
return;
}
// Client isn't focused, we need to show a notification.
return self.registration.showNotification('Had to show a notification.');
});
event.waitUntil(promiseChain);
Inviare messaggi a una pagina da un evento push
Abbiamo notato che puoi saltare la visualizzazione di una notifica se l'utente si trova attualmente sul tuo sito. Ma cosa succede se vuoi comunque far sapere all'utente che si è verificato un evento, ma viene inviata una notifica troppo pesante?
Un approccio è inviare un messaggio dal service worker alla pagina, in questo modo la pagina web può mostrare una notifica o un aggiornamento all'utente per informarlo dell'evento. Questo è utile per situazioni in cui una notifica discreta nella pagina risulta migliore e più amichevole per l'utente.
Supponiamo che abbiamo ricevuto un push, verificato che la nostra app web sia attualmente selezionata. quindi possiamo "pubblicare un messaggio" su ogni pagina aperta, in questo modo:
const promiseChain = isClientFocused().then((clientIsFocused) => {
if (clientIsFocused) {
windowClients.forEach((windowClient) => {
windowClient.postMessage({
message: 'Received a push message.',
time: new Date().toString(),
});
});
} else {
return self.registration.showNotification('No focused windows', {
body: 'Had to show a notification instead of messaging each page.',
});
}
});
event.waitUntil(promiseChain);
In ogni pagina ascoltiamo i messaggi aggiungendo un evento apposito listener:
navigator.serviceWorker.addEventListener('message', function (event) {
console.log('Received a message from service worker: ', event.data);
});
In questo listener di messaggi, puoi fare tutto ciò che vuoi, visualizzare un'interfaccia utente personalizzata sulla pagina o ignorarlo completamente.
Vale anche la pena notare che, se non definisci un listener di messaggi nella pagina web, dal service worker non farà nulla.
Memorizzare una pagina nella cache e aprire una finestra
Uno scenario che esula dall'ambito di questa guida, ma che vale la pena discutere, è che puoi migliorare l'esperienza utente complessiva della tua app web memorizzando nella cache le pagine web che ti aspetti che gli utenti visitino dopo facendo clic sulla notifica.
È necessario che il service worker sia configurato per gestire gli eventi fetch
,
ma se implementi un listener di eventi fetch
, assicurati di utilizzare
sfruttalo nel tuo evento push
memorizzando nella cache la pagina e gli asset
che ti occorre per mostrare la notifica.
Compatibilità del browser
L'evento notificationclose
Clients.openWindow()
ServiceWorkerRegistration.getNotifications()
clients.matchAll()
Per ulteriori informazioni, consulta questa introduzione ai service worker post.
Passaggi successivi
- Panoramica delle notifiche push web
- Come funziona il push
- Iscrizione di un utente
- Esperienza utente con autorizzazione
- Invio di messaggi con le librerie push sul web
- Protocollo web push
- Gestione degli eventi push
- Visualizzazione di una notifica
- Comportamento delle notifiche
- Modelli di notifica comuni
- Domande frequenti sulle notifiche push
- Problemi comuni e segnalazione di bug