PWA推送通知在iOS上为啥不生效?

❤素香 阅读 33

我用Push API做了个PWA,安卓上能正常收推送,但iOS Safari完全没反应,是不是iOS根本不支持?

我已经注册了service worker,也调用了Notification.requestPermission(),安卓端一切正常。但在iPhone上,连权限弹窗都不出现,控制台也没报错。

查了下资料说iOS 16.4开始支持Web Push,但我测试的设备是iOS 17,还是不行。是不是还需要额外配置什么?比如apple-app-site-association或者APNs?

现在我的manifest.json里有"display": "standalone",sw.js也注册成功了,但navigator.serviceWorker.ready.then(...)之后调用pushManager.subscribe()直接没动静。

我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
百里彦杰
iOS对PWA推送通知的支持确实有点坑。首先你得确认你的web服务器用的是HTTPS,这不光是安全要求,也是PWA的基础。

接着说下配置。iOS 16.4开始支持Web Push没错,但你需要在manifest.json里加上"start_url": "./",而且最好指定一个scope。还有个容易忽略的点,就是manifest里的short_name不能太长,建议控制在12个字符以内。

然后就是service worker这块。记得在sw.js里要监听push事件,写个简单的处理函数就行,别忘了加event.waitUntil()防止过早退出。代码大概是这样

self.addEventListener('push', function(event) {
const data = event.data ? event.data.text() : '默认消息';
event.waitUntil(
self.registration.showNotification('新消息', {
body: data
})
);
});


说到权限请求,iOS上需要用户至少点击一次页面才会触发requestPermission()。这是系统限制,没什么好办法绕过去。

最后提醒一下,调试时注意看Safari的开发者工具日志。虽然不像Chrome那么详细,但有时候能发现一些有用的信息。要是实在不行,考虑给苹果提个bug反馈吧,毕竟他们家系统总有些奇奇怪怪的问题。
点赞
2026-03-29 13:35
W″佳丽
这题我熟,去年在这个坑里躺了三天,血泪教训分享给你。

iOS支持Web Push,但它的限制比安卓严得多,有几个必须满足的条件,少一个都不行。

第一,也是最关键的,iOS必须在"添加到主屏幕"后才能使用推送。直接在Safari浏览器里访问是拿不到推送权限的,Push API在Safari浏览器模式下根本就是残废状态。你必须把PWA添加到主屏幕,从主屏幕图标启动才行。

第二,订阅操作必须由用户手势触发。不能在页面加载时自动调用,必须放在按钮点击事件里。你提到的pushManager.subscribe()没动静,大概率就是这个问题。代码要这样写:

// 必须在用户交互事件中调用
document.getElementById('subscribeBtn').addEventListener('click', async () => {
const permission = await Notification.requestPermission();
if (permission !== 'granted') {
console.log('用户拒绝了权限');
return;
}

const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('你的VAPID公钥')
});

// 把subscription发给后端保存
});

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;
}


第三,manifest.json里display设成standalone是对的,但还需要确保有nameshort_name字段,以及正确的start_url。另外建议加上"prefer_related_applications": false,防止iOS误判。

第四,不需要apple-app-site-association,那是Universal Links的配置,跟Web Push没关系。也不需要单独配置APNs,Web Push走的是苹果的Web Push服务,后端用标准的Web Push协议(VAPID)发推送就行,苹果会自动转成APNs推送到设备。

排查步骤给你列一下:

先确认是从主屏幕图标启动的PWA,不是Safari。然后在控制台输入navigator.serviceWorker.ready.then(r => console.log(r.pushManager)),看看pushManager是否存在。如果存在,把订阅逻辑绑到按钮上,点击后再试。

还有个坑,iOS的权限弹窗只会弹一次,如果用户点了拒绝或者关掉了,以后再调用requestPermission()会直接返回denied,不会弹窗。这种情况得去系统设置里手动改权限,或者删了主屏幕图标重新添加。

最后提醒一句,iOS模拟器不支持Web Push测试,必须用真机。我当初在模拟器上折腾了一整天才发现这个问题。
点赞 1
2026-03-01 02:04