iOS 16.4.3 Safari中Push API无法正常工作的问题求助
问题:iOS 16.4.3 Safari PWA中推送通知无法正常工作
我实现了Push和Notification API,在Mac OS的Chrome、Safari,Windows的Chrome等浏览器中均可正常运行,但在iOS 16.4.3的Safari(已添加至主屏作为PWA)中存在问题:点击按钮#enable-notifications后,通知授权弹窗正常弹出,但授权后无任何反应,后端也未收到请求。经测试,navigator.serviceWorker.controller返回null。后续修改JS代码后,出现通知授权弹窗两次,且其他浏览器中服务端也无法收到请求的新问题。
原始应用JS代码
document.getElementById("enable-notifications").addEventListener("click", () => { main(); }); const check = () => { if (!('serviceWorker' in navigator)) { throw new Error('No Service Worker support!') } if (!('PushManager' in window)) { throw new Error('No Push API Support!') } } const registerServiceWorker = async () => { const swRegistration = await navigator.serviceWorker.register('/assets/js/order-dashboard/serviceworker.js'); return swRegistration; } const requestNotificationPermission = async () => { Promise.resolve(Notification.requestPermission()).then(function(permission) { if (permission !== 'granted') { throw new Error('Permission not granted for Notification') } }); } const main = async () => { check(); const swRegistration = await registerServiceWorker(); const permission = await requestNotificationPermission(); } const showLocalNotification = (title, body, swRegistration) => { const options = { body, }; swRegistration.showNotification(title, options); }
serviceworker.js代码
// urlB64ToUint8Array 用于将base64公钥编码为订阅选项所需的ArrayBuffer const urlB64ToUint8Array = base64String => { const padding = '='.repeat((4 - (base64String.length % 4)) % 4) const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/') const rawData = atob(base64) const outputArray = new Uint8Array(rawData.length) for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i) } return outputArray } // saveSubscription 将订阅信息保存到后端 const saveSubscription = async subscription => { const SERVER_URL = 'https://good-months-invite-109-132-150-239.loca.lt/save-subscription' const response = await fetch(SERVER_URL, { method: 'post', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(subscription), }) console.log(response); return response.json() } self.addEventListener('activate', async () => { // 仅在Service Worker激活时调用一次 try { const applicationServerKey = urlB64ToUint8Array( 'BDLVKNq32B-Dr3HRd4wQ2oNZL9mw5JAGhB1XGCdKlDE9_KDEw7uTOLuPKH-374RRolaa0rr7UyfrJd7tvRvp304' ) const options = { applicationServerKey, userVisibleOnly: true } const subscription = await self.registration.pushManager.subscribe(options) const response = await saveSubscription(subscription) console.log(response) } catch (err) { console.log('Error', err) } }) self.addEventListener("push", function(event) { if (event.data) { console.log("Push event!!! ", event.data.text()); showLocalNotification("Yolo", event.data.text(), self.registration); } else { console.log("Push event but no data"); } }); const showLocalNotification = (title, body, swRegistration) => { const options = { body // 可在此添加更多属性,如icon、image、vibrate等 }; swRegistration.showNotification(title, options); };
Node.js后端代码
const express = require('express') const cors = require('cors') const bodyParser = require('body-parser') const webpush = require('web-push') const app = express() app.use(cors()) app.use(bodyParser.json()) const port = 4000 app.get('/', (req, res) => res.send('Hello World!')) const dummyDb = { subscription: null } // 内存中的模拟存储,请勿在生产环境使用 const saveToDatabase = async subscription => { // 此处应替换为实际的数据库存储逻辑 dummyDb.subscription = subscription } // 保存订阅信息的接口 app.post('/save-subscription', async (req, res) => { const subscription = req.body await saveToDatabase(subscription) console.log("saved"); res.json({ message: 'success' }) }) const vapidKeys = { publicKey: 'BDLVKNq32B-Dr3HRd4wQ2oNZL9mw5JAGhB1XGCdKlDE9_KDEw7uTOLuPKH-374RRolaa0rr7UyfrJd7tvRvp304', privateKey: 'BGbNIt2twl1XsbDHPNe_w6FrKsWcZrys6anByEKyCGo', } // 配置VAPID密钥 webpush.setVapidDetails( 'mailto:myuserid@email.com', vapidKeys.publicKey, vapidKeys.privateKey ) // 向订阅设备发送通知的函数 const sendNotification = (subscription, dataToSend) => { webpush.sendNotification(subscription, dataToSend) } // 测试发送通知的接口 app.get('/send-notification', (req, res) => { const subscription = dummyDb.subscription // 从数据库获取订阅信息 const message = 'Hello World' sendNotification(subscription, message) res.json({ message: 'message sent' }) }) app.listen(port, () => console.log(`Example app listening on port ${port}!`))
修改后的应用JS代码
document.getElementById("enable-notifications").addEventListener("click", (event) => { event.preventDefault() askNotificationPermission().then(alert).then(registerServiceWorker); }) function askNotificationPermission() { return new Promise((resolve, reject) => { if (checkNotificationPromise()) { Notification.requestPermission().then(resolve); } else { Notification.requestPermission(resolve) } }) } function checkNotificationPromise() { try { Notification.requestPermission().then(); } catch(e) { return false; } return true; } const registerServiceWorker = async () => { // alert("registering service worker"); const swRegistration = await navigator.serviceWorker.register('/assets/js/order-dashboard/serviceworker.js'); // alert(swRegistration.active); console.log(swRegistration); return swRegistration; }
内容的提问来源于stack exchange,提问作者O'Niel
相关产品推荐
相关产品推荐

