仅用Push API获取FCM令牌,无需Notifications API是否可行?
问题描述
- 正在使用Firebase Cloud Messaging (FCM),Firebase JS SDK存在相同问题:希望仅使用Push API实现浏览器内消息传递,完全不依赖Notifications API,但调用Messaging的
getToken()时似乎需要Notifications API支持,只想获取用于Push API的令牌,不需要Notifications API,询问是否可行。 - 在Service Worker上下文调用
getToken()时,总是返回与Notifications相关的错误:ReferenceError: Can't find variable: Notification,且不想使用Notifications API。 - 补充说明:
- 调用
getToken()会自动调用requestPermission(),无需单独调用; - 该错误仅出现在不支持Notifications API的浏览器中;
- Push API与Notifications API是独立的两个Web API。
- 调用
- 代码示例:
getToken(fbMessaging, { vapidKey: '..' })
解决方案
FCM的JS Messaging SDK在设计上与Notifications API强绑定,getToken()方法内部会依赖Notification对象完成权限处理和令牌生成逻辑,因此在不支持Notifications API的环境中必然会报错,无法直接通过FCM SDK实现仅依赖Push API获取令牌的需求。
如果要完全脱离Notifications API的依赖,建议直接使用原生Push API实现推送订阅与令牌获取,具体步骤如下:
- 在Service Worker中监听
push事件,直接处理推送消息(无需显示通知,可在回调中处理业务数据); - 在主页面注册Service Worker,通过
registration.pushManager.subscribe()方法获取推送订阅对象,该对象包含用于推送的端点信息(作用等价于FCM令牌); - 将订阅对象发送至后端服务器保存,后续可通过FCM的HTTP v1 API或其他推送服务,基于该订阅信息发送推送消息。
原生Push API获取订阅的示例代码:
// 主页面代码 async function subscribeToPush() { const registration = await navigator.serviceWorker.register('/sw.js'); const subscription = await registration.pushManager.subscribe({ userVisibleOnly: false, // 关键:设置为false,无需通知可见性 applicationServerKey: urlBase64ToUint8Array('你的VAPID公钥') }); // 将subscription发送到后端保存 await fetch('/api/save-subscription', { method: 'POST', body: JSON.stringify(subscription), headers: { 'Content-Type': 'application/json' } }); } // 辅助函数:将base64格式的VAPID密钥转换为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); return Uint8Array.from([...rawData].map(char => char.charCodeAt(0))); } // Service Worker代码(sw.js) self.addEventListener('push', (event) => { const data = event.data?.json() || {}; // 在这里处理推送数据,比如发送到主页面或直接执行业务逻辑 event.waitUntil( self.clients.matchAll({ type: 'window' }).then(clients => { clients.forEach(client => { client.postMessage({ type: 'PUSH_MESSAGE', payload: data }); }); }) ); });
需要注意,userVisibleOnly设置为false时,部分浏览器可能有额外限制,需确保使用场景符合浏览器政策要求。
内容的提问来源于stack exchange,提问作者Steve Kennedy
相关产品推荐
相关产品推荐

