乐闻世界logo
搜索文章和话题

How does PWA implement push notification functionality? What steps and components are required?

2月18日 21:53

PWA push notification functionality uses Web Push API and Service Worker to send notifications when the user hasn't opened the app. Here's a complete implementation:

Core Components of Push Notifications

1. Push API

Used to receive messages pushed from the server

2. Notification API

Used to display notifications

3. Service Worker

Handles push events in the background

Steps to Implement Push Notifications

Step 1: Generate VAPID Keys

VAPID (Voluntary Application Server Identification) is used to verify the identity of the push server.

bash
# Generate keys using web-push npm install -g web-push web-push generate-vapid-keys

Generated result:

shell
Public Key: <your-public-key> Private Key: <your-private-key>

Step 2: Request Push Subscription Permission

javascript
// Request subscription in main thread async function subscribeUser() { // Check browser support if (!('serviceWorker' in navigator) || !('PushManager' in window)) { console.log('Push messaging is not supported'); return; } try { // Get Service Worker registration const registration = await navigator.serviceWorker.ready; // Request subscription const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array('<your-public-key>') }); console.log('User is subscribed:', subscription); // Send subscription info to server await saveSubscriptionToServer(subscription); } catch (error) { console.log('Failed to subscribe the user:', error); } } // Convert Base64 string to Uint8Array function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/-/g, '+') .replace(/_/g, '/'); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; }

Step 3: Handle Push Events in Service Worker

javascript
// sw.js self.addEventListener('push', event => { console.log('Push event received:', event); let data = { title: 'New Message', body: 'You have a new message', icon: '/icons/icon-192x192.png', badge: '/icons/badge-72x72.png' }; // Parse push data if (event.data) { try { data = { ...data, ...event.data.json() }; } catch (error) { data.body = event.data.text(); } } // Show notification const options = { body: data.body, icon: data.icon, badge: data.badge, vibrate: [200, 100, 200], data: { dateOfArrival: Date.now(), primaryKey: 1 }, actions: [ { action: 'explore', title: 'View Details', icon: '/icons/explore.png' }, { action: 'close', title: 'Close', icon: '/icons/close.png' } ] }; event.waitUntil( self.registration.showNotification(data.title, options) ); });

Step 4: Handle Notification Click Events

javascript
self.addEventListener('notificationclick', event => { console.log('Notification click received:', event); event.notification.close(); // Handle different actions if (event.action === 'explore') { // Open specific page event.waitUntil( clients.openWindow('/details') ); } else if (event.action === 'close') { // Close notification, do nothing else return; } else { // Default action: open app home page event.waitUntil( clients.matchAll({ type: 'window' }).then(clientList => { // If there's an open window, focus on it for (const client of clientList) { if (client.url === '/' && 'focus' in client) { return client.focus(); } } // Otherwise open new window if (clients.openWindow) { return clients.openWindow('/'); } }) ); } });

Step 5: Send Push Messages from Server

Using Node.js and web-push library:

javascript
const webpush = require('web-push'); // Set VAPID keys const vapidKeys = { publicKey: '<your-public-key>', privateKey: '<your-private-key>' }; webpush.setVapidDetails( 'mailto:your-email@example.com', vapidKeys.publicKey, vapidKeys.privateKey ); // Send push notification async function sendPushNotification(subscription, data) { try { await webpush.sendNotification(subscription, JSON.stringify(data)); console.log('Push notification sent successfully'); } catch (error) { console.error('Error sending push notification:', error); // If subscription is invalid, remove from database if (error.statusCode === 410) { await removeSubscriptionFromDatabase(subscription); } } } // Example: Send notification to all subscribers async function sendToAllSubscribers(message) { const subscriptions = await getAllSubscribersFromDatabase(); const promises = subscriptions.map(subscription => { return sendPushNotification(subscription, { title: 'New Notification', body: message, icon: '/icons/icon-192x192.png' }); }); await Promise.allSettled(promises); }

Advanced Push Notification Features

1. Silent Push

javascript
self.addEventListener('push', event => { if (!event.data) return; const data = event.data.json(); // If silent push, don't show notification if (data.silent) { event.waitUntil( // Execute background tasks, like syncing data syncData() ); return; } // Otherwise show notification event.waitUntil( self.registration.showNotification(data.title, { body: data.body, icon: data.icon }) ); });

2. Scheduled Push

javascript
// Use setTimeout for delayed push self.addEventListener('push', event => { const data = event.data.json(); if (data.delay) { setTimeout(() => { self.registration.showNotification(data.title, { body: data.body }); }, data.delay); } else { self.registration.showNotification(data.title, { body: data.body }); } });

3. Rich Media Notifications

javascript
self.addEventListener('push', event => { const data = event.data.json(); const options = { body: data.body, icon: data.icon, image: data.image, // Large image badge: data.badge, // Small icon vibrate: [200, 100, 200], sound: '/sounds/notification.mp3', tag: 'unique-tag', // Used to replace notifications with same tag renotify: true, // Alert user when notification is repeated requireInteraction: true, // Requires user interaction to close actions: [ { action: 'reply', title: 'Reply', icon: '/icons/reply.png', type: 'text', placeholder: 'Enter reply' } ], data: { // Custom data url: data.url } }; event.waitUntil( self.registration.showNotification(data.title, options) ); });

Best Practices for Push Notifications

  1. Timing of Permission Request: Request when user has clear need, not on page load
  2. Notification Content: Provide valuable information, avoid spam notifications
  3. Frequency Control: Don't send notifications too frequently
  4. Personalization: Customize notification content based on user preferences
  5. Actionable: Provide useful action buttons
  6. Error Handling: Properly handle subscription invalidation
  7. Testing: Test notification effects on different devices and browsers

Browser Compatibility

  • Chrome, Edge, Firefox: Full support
  • Safari: Partial support (iOS 16.4+)
  • Requires user authorization

Debugging Push Notifications

Use Chrome DevTools:

  1. Open Application panel
  2. View Service Workers tab
  3. Click "Push" button to simulate push
  4. View notification display effect
标签:PWA