Chrome扩展v3中GCM/FCM获取推送注册令牌失败求助
问题:Manifest V3 Chrome扩展集成Firebase推送通知无法获取注册令牌
我开发了一款manifest_version为3的Chrome扩展,需集成Firebase实现推送通知功能,已在Firebase控制台创建对应项目,但无法获取发送推送所需的注册令牌。
尝试方案一:使用chrome.gcm API
清单配置
{ "name": "Notifications", "version": "1.0.0.0", "manifest_version": 3, "action": { "default_popup": "popup.html" }, "permissions": [ "notifications", "gcm" ], "background": { "service_worker": "background.js" } }
代码(background.js)
chrome.runtime.onInstalled.addListener((details) => { const senderIds = ['****']; chrome.gcm.register(senderIds, (registrationId) => { if (chrome.runtime.lastError) { console.error(`Registration failed: ${chrome.runtime.lastError.message}`); return; } console.log('Registration ID:', registrationId); }); });
遇到的问题
在service worker中始终报错:Asynchronous operation is pending
尝试方案二:使用Firebase SDK
清单配置
{ "manifest_version": 3, "name": "FCM Chrome Extension", "version": "1.0", "permissions": [ "notifications", "storage" ], "background": { "service_worker": "background.js" //"type": "module" }, "action": { "default_popup": "popup.html" }, "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'self'" }, "web_accessible_resources": [ { "resources": [ "firebase-messaging-sw.js" ], "matches": [ "<all_urls>" ] } ], "icons": { "48": "images/icon.png" } }
代码(background.js)
importScripts('firebase/firebase-app-compat.js'); importScripts('firebase/firebase-messaging-compat.js'); const firebaseConfig = { apiKey: "*", authDomain: "*", projectId: "*", storageBucket: "*", messagingSenderId: "*", appId: "*", measurementId: "*" }; firebase.initializeApp(firebaseConfig); console.log('here'); // Retrieve Firebase Messaging object const messaging = firebase.messaging(); console.log(messaging); async function fetchToken() { try { const token = await getToken(messaging, { vapidKey: '*************' }); console.log('FCM Token:', token); } catch (error) { console.error('Error getting token:', error); } } fetchToken();
遇到的问题
- 本地安装Firebase后无法引用内部函数;
- 使用静态Firebase文件时清单加载失败,添加service worker的
module类型后浏览器提示不支持; - 尝试通过webpack打包background脚本未解决问题;
- 最终加载v9.0.0兼容版的Firebase App和Messaging JS文件,虽能获取messaging对象,但
getToken函数仍无法正常工作。
解决方案
针对方案一(chrome.gcm API)的修复
Asynchronous operation is pending错误源于Manifest V3 service worker的异步上下文限制,改用Promise封装调用即可解决:
chrome.runtime.onInstalled.addListener(async (details) => { const senderIds = ['你的Firebase发件人ID']; try { const registrationId = await new Promise((resolve, reject) => { chrome.gcm.register(senderIds, (id) => { const err = chrome.runtime.lastError; if (err) reject(err); else resolve(id); }); }); console.log('Registration ID:', registrationId); // 将令牌存储到本地备用 await chrome.storage.local.set({ fcmToken: registrationId }); } catch (err) { console.error(`Registration failed: ${err.message}`); } });
同时确认:
- 清单中已正确声明
gcm权限; - Sender ID为Firebase控制台项目设置>云消息传递中的官方发件人ID。
针对方案二(Firebase SDK)的正确配置
1. 清单文件调整
- 移除
web_accessible_resources中对firebase-messaging-sw.js的声明,Manifest V3扩展的service worker无需对外暴露; - 修改内容安全策略,允许加载Firebase CDN脚本:
"content_security_policy": { "extension_pages": "script-src 'self' https://www.gstatic.com/firebasejs/; object-src 'self'" }
- 不要给background service worker设置
type: module,Firebase兼容版不支持ES模块导入。
2. 修正Firebase初始化代码
getToken是messaging实例的方法,需正确调用,同时补充权限处理逻辑:
importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js'); importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging-compat.js'); const firebaseConfig = { // 你的Firebase项目配置 }; firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); // 配置后台消息处理 messaging.onBackgroundMessage((payload) => { const notificationTitle = payload.notification.title; const notificationOptions = { body: payload.notification.body, icon: '/images/icon.png' }; self.registration.showNotification(notificationTitle, notificationOptions); }); async function fetchToken() { try { // 使用Firebase控制台生成的VAPID公钥 const token = await messaging.getToken({ vapidKey: '你的VAPID公钥' }); console.log('FCM Token:', token); await chrome.storage.local.set({ fcmToken: token }); } catch (error) { console.error('Error getting token:', error); // 处理未授权情况 if (error.code === 'messaging/permission-blocked' || error.code === 'messaging/permission-default') { const permission = await Notification.requestPermission(); if (permission === 'granted') { fetchToken(); } } } } // 在扩展安装/更新、权限变更时触发令牌获取 chrome.runtime.onInstalled.addListener(fetchToken); chrome.notifications.onPermissionLevelChanged.addListener((level) => { if (level === 'granted') { fetchToken(); } });
3. 关键注意事项
- 直接使用Firebase CDN脚本,避免本地文件路径或打包问题;
- VAPID公钥需与Firebase控制台项目设置>云消息传递>Web配置中生成的密钥对一致;
- 必须等待用户授予通知权限后,
getToken才能成功获取令牌; - 利用Chrome的storage API持久化令牌,避免service worker重启后丢失。
内容的提问来源于stack exchange,提问作者Shivani Wadhwa
相关产品推荐
相关产品推荐

