PWA 的 Background Sync 在 iOS 上为啥不生效?
我用 PWA 做了个待办事项 App,想在用户离线时把新增任务暂存,等网络恢复后自动同步。我在 service worker 里注册了 background sync,Chrome 模拟器上能跑,但 iOS Safari 完全没反应。
查了下资料说 iOS 对 Background Sync 支持不好,但不确定是不是我写法有问题。我试过这样注册:
navigator.serviceWorker.ready.then(registration => {
return registration.sync.register('sync-tasks');
});
service worker 里也监听了 sync 事件,可 iOS 上连事件都没触发。这功能现在到底能不能在 iOS 用?还是得自己轮询?
根本原因是 WebKit 团队(也就是 Safari 的内核)出于对电池续航和用户隐私的考虑,一直没有实现这个标准。虽然 Chrome 和 Android 上这玩意儿很好用,但在 iOS 的 Web 环境里,
registration.sync.register这行代码目前就是摆设,它既不会报错,也不会生效,完全被忽略了。那是不是就没办法了?也不至于,虽然原生的 Background Sync 用不了,但我们可以用一套兼容方案来覆盖 iOS 和 Android。核心思路就是:能原生用原生,不能用就用“网络状态监听 + Service Worker 消息通信”来模拟。
具体怎么做,分两步走。
第一步,在你的主页面代码里做一个特性检测。如果浏览器支持 Background Sync 就用原生的;如果不支持(比如 iOS),就注册一个
online事件监听器。当网络恢复时,手动通知 Service Worker 去干活。代码大概这么写:
第二步,去你的 Service Worker 文件里,把“同步任务”这个逻辑抽离成一个独立的函数。然后既监听
sync事件(给 Android 用),也监听message事件(给 iOS 用)。Service Worker 的代码改造成这样:
这里有个细节要特别注意,也是 iOS 这种方案和 Android 原生方案最大的区别:原生 Background Sync 是真正的“后台”,即使用户关了浏览器,只要网络恢复,系统会唤醒 SW 执行。但 iOS 的
online事件必须依赖用户打开浏览器或者你的 PWA 还在前台运行时才能触发。如果用户离线关了 App,过一会恢复网络但没打开 App,那数据还是同步不上去。在目前的 iOS 生态下,这是最稳妥的“无侵入式”方案。至于轮询,千万别用,在 Web 环境里轮询太耗电,而且很容易被系统挂起,体验极差。
总结一下:你的代码没写错,是 iOS 不给权限。用上面这套“双保险”写法,Android 享受真后台同步,iOS 享受“打开即同步”,能解决 99% 的场景。