Manifest V3 Chrome扩展在Edge中FCM通知重复显示问题求助
Edge浏览器FCM推送重复显示通知问题解决指南
问题说明
基于Manifest V3开发的Chrome扩展,通过FCM API V1实现消息推送,在Chrome中运行正常,但在MS Edge中触发推送时,会同时弹出系统默认通知(“此网站已在后台更新”)和自定义通知,需要仅保留自定义通知。
提供的代码文件
manifest.json
{ "name": "Staines Memorial College Notifications", "version": "1.0.1", "description": "Recieve notifications for Staines Memorial College and the Diary App.", "manifest_version": 3, "author": "Braydan Mengel - Staines Memorial College", "action": { "default_popup": "Ext_Status.html", "default_title": "Staines Memorial College Notifications Extension" }, "permissions": [ "notifications", "background", "storage" ], "background": { "service_worker": "background.js", "type": "module" }, "icons": { "48": "Images/ExtensionIcon48.png", "128": "Images/ExtensionIcon128.png" } }
background.js
import { getMessaging } from "./firebase/firebase-messaging-sw.js"; import { getToken } from "./firebase/firebase-messaging.js"; import { initializeApp } from "./firebase/firebase-app.js"; //init firebase initializeApp({ apiKey: "", authDomain: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "", measurementId: "" }); //global variables var UserID; //chrome local storage chrome.storage.local.get(["userData"]).then((result) => { if (result.userData === undefined) { chrome.tabs.create({ url: chrome.runtime.getURL("Ext_Login.html") }); } else { UserID = result.userData.uuid; setTimeout(() => { RegTopic(); }, 1000) } }); async function RegTopic() { //get the gcm device token and send it to the server const token = await getToken(getMessaging(), { serviceWorkerRegistration: self.registration }); const details = { "userid": UserID, "token": token }; fetch("https://example.com/ins/tokens/fcm/regToken", { method: "POST", headers: { "Content-Type": "application/json; charset=UTF-8" }, body: JSON.stringify(details) }) .then(response => response.json()) .then(data => { if (data.message === 'Registered') { console.log('Registered token successfully!'); } }) .catch(error => { setTimeout(() => { RegTopic(); }, 5000) console.error("Error:", error); }); } //when a message is received self.addEventListener('push', function (event) { const Message = event.data.json(); if (Message.data.link === "NONE") { // No link found if (Message.data.priority === "0") { // Priority is set to 0 meaning Normal const showNotification = self.registration.showNotification(`Staines Notifications - ${Message.data.title}`, { icon: "../Images/Notify.png", body: Message.data.body, requireInteraction: false, data: { notificationid: Message.data.notificationid, linkOpening: Message.data.link } }); event.waitUntil(showNotification); } else if (Message.priority === "1") { // Priority is set to 1 meaning Important const showNotification = self.registration.showNotification(`Staines Notifications - ${Message.data.title}`, { icon: "../Images/Notify.png", body: Message.data.body, requireInteraction: true, data: { notificationid: Message.data.notificationid, linkOpening: Message.data.link } }); event.waitUntil(showNotification); } } else { // Link is included; priority is set to 1 meaning Important by default const showNotification = self.registration.showNotification(`Staines Notifications - ${Message.data.title}`, { icon: "../Images/Notify.png", body: Message.data.body, requireInteraction: true, data: { notificationid: Message.data.notificationid, linkOpening: Message.data.link } }); event.waitUntil(showNotification); } }); //Login message handler chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === 'login') { UserID = message.data.userid; const response = { status: 'success' }; sendResponse(response); RegTopic(); } }); // Notification handlers self.addEventListener('notificationclick', function (event) { const clickedNotification = event.notification; const linkOpening = clickedNotification.data.linkOpening; if (linkOpening !== 'NONE') { event.waitUntil( clients.openWindow(linkOpening) ); } }); self.addEventListener('notificationclose', function (event) { const clickedNotification = event.notification; const linkOpening = clickedNotification.data.linkOpening; if (linkOpening !== 'NONE') { event.waitUntil( clients.openWindow(linkOpening) ); } });
补充信息
- 使用Firebase 9.0.0版本的核心脚本(firebase-app.js、firebase-messaging.js、firebase-messaging-sw.js),已随扩展打包
- 扩展目录包含根目录核心文件、
Images资源文件夹、firebase脚本文件夹及登录/状态页面
解决方法
Edge出现默认通知的核心原因是:当FCM推送仅包含data字段时,Edge会自动生成默认通知,而Chrome不会触发该行为。以下两种方案均可解决:
方案一:客户端拦截默认行为
在Service Worker的push事件开头添加event.preventDefault(),阻止浏览器生成默认通知,代码修改如下:
self.addEventListener('push', function (event) { // 阻止浏览器默认通知逻辑 event.preventDefault(); const Message = event.data.json(); // 后续自定义通知逻辑保持不变 if (Message.data.link === "NONE") { // ... 原代码 } else { // ... 原代码 } });
此方法无需修改服务器端推送逻辑,直接在客户端拦截,操作简单。
方案二:服务器端调整推送消息结构
在发送FCM消息时,添加webpush.fcm_options.link字段,设置为扩展内的页面地址(比如状态页),Edge识别到是扩展内部地址后,不会弹出默认通知。示例推送请求体:
{ "message": { "token": "目标设备的FCM Token", "data": { "title": "自定义标题", "body": "自定义内容", "link": "跳转链接", "priority": "1", "notificationid": "通知ID" }, "webpush": { "fcm_options": { "link": "chrome-extension://你的扩展ID/Ext_Status.html" } } } }
注:替换你的扩展ID为实际的扩展ID,该地址不影响自定义跳转逻辑,仅用于屏蔽Edge默认通知。
测试注意事项
- 修改代码后需重新加载扩展
- 重新注册FCM Token,确保新配置生效
内容的提问来源于stack exchange,提问作者Braydan
相关产品推荐
相关产品推荐

