实现消息实时推送的Push API实战经验与避坑指南

长孙怡瑶 移动 阅读 1,671
赞 12 收藏
二维码
手机扫码查看
反馈

Push API的坑,我踩了不止一个

最近在搞移动端的消息推送功能,用到了Push API。听起来挺简单的一个API,结果折腾了我整整两天。这里记录下我遇到的几个坑和最终解决方案,给同样踩坑的小伙伴一点参考。

实现消息实时推送的Push API实战经验与避坑指南

第一个坑:用户明明点了允许,却收不到推送

最开始的问题是这样的:用户点击允许通知权限后,服务器也显示推送成功了,但设备就是收不到消息。这里我踩了个大坑,浪费了不少时间。

后来发现是service worker没正确注册。很多人不知道,Push API其实是依赖service worker工作的。即使你拿到了用户授权,如果sw文件路径不对或者没加载成功,消息还是发不过来。

这是我的最终解决方案:

// 注册service worker
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('Service Worker registered with scope:', registration.scope);
  }).catch(function(error) {
    console.error('Service Worker registration failed:', error);
  });
}

// 请求通知权限
Notification.requestPermission().then(permission => {
  if (permission === 'granted') {
    console.log('Notification permission granted.');
  }
});

注意这里的sw.js一定要放在根目录,因为它的作用域是由其位置决定的。我之前把它放错了位置,导致整个功能都跑不起来。

第二个坑:payload大小限制

这个坑更隐蔽。我在测试环境一切正常,结果上线后发现部分消息接收失败。折腾了半天才发现是payload大小超限了。

根据规范,push message的payload不能超过4KB。但是不同浏览器的实现有差异,比如Chrome就严格限制在4KB以内,而Firefox稍微宽松一些。

解决方法是把重要数据存在服务器端,只传递一个消息ID:

self.addEventListener('push', function(event) {
  const data = event.data.json();
  const messageId = data.id;

  // 从服务器获取完整消息内容
  event.waitUntil(
    fetch(https://jztheme.com/api/message/${messageId}).then(response => {
      return response.json();
    }).then(messageData => {
      const title = messageData.title;
      const options = {
        body: messageData.body,
        icon: messageData.icon
      };
      return self.registration.showNotification(title, options);
    })
  );
});

第三个坑:后台同步问题

还有一个容易忽略的问题是,当应用在后台时,有时候收不到推送。这里需要注意两点:

  • 确保manifest.json配置正确
  • 使用background sync做补充

我的manifest.json是这么配的:

{
  "name": "Push Demo",
  "short_name": "PushDemo",
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#ffffff",
  "gcm_sender_id": "1234567890" // 这里要替换成自己的GCM sender ID
}

一些额外的注意事项

1. 不同浏览器对Push API的支持程度不一样,建议在caniuse上查一下最新支持情况
2. 记得处理各种异常情况,比如网络断开、服务端错误等
3. 在开发过程中,推荐使用navigator.serviceWorker.ready来确保sw已经ready

以上是我踩坑后的总结,虽然现在功能基本跑通了,但感觉还有很多可以优化的地方。如果你有更好的方案欢迎评论区交流。

顺便吐槽一句,这玩意儿调试起来是真的麻烦,尤其是涉及到service worker的时候,刷新缓存什么的特别烦人。不过话说回来,一旦调通了还挺有成就感的。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论