后端【免费下载链接】angularfireAngular Firebase ❤️项目地址https://gitcode.com/gh_mirrors/an/angularfire点击查看免费下载Firebase Cloud MessagingFCM让你能为每台设备注册唯一的 FCM tokenFirebase Installation ID随后通过 Firebase Cloud Functions 在服务端按需向这些 token 编程式推送通知。本文以 AngularFire 的现代 tree-shakable APIangular/fire/messaging为主线完整讲解从依赖注入、Service Worker 搭建、register/onRegistered实例注册到使用 Firebase Admin SDK 发送通知含 token 缓存的端到端实战方案。读完本文你将能在 Angular 应用中安全地请求通知权限、注册并跟踪 FCM 实例、接收前台消息并在 Cloud Functions 中按用户精准推送通知。FCM 在 Angular 应用中的角色Firebase Cloud Messaging 允许你把每台设备注册为唯一的 FCM token之后就可以通过 Firebase Cloud Functions 在服务端向这些 token 编程式发送通知。是否把这些 token 同步到 Firebase 数据库、用于应用的其他层级完全由应用自己决定——例如向所有管理员发送通知这类场景你通常需要把 FCM token 存放在 user 集合、其子集合或另一个权限不同的集合中这样才能在服务端按用户查询到对应 token。从 AngularFire 21 开始getToken和deleteToken在 firebase 12.18 中被弃用并将被移除官方推荐改用registeronRegistered、unregisteronUnregistered这套新模型。这一版本对齐要求也体现在 docs/version-21-upgrade.md 中ng update angular/fire会把firebase依赖对齐到^12.18.0避免新旧 SDK 副本并存导致运行时对象互相排斥。本文全部基于新 API 展开。依赖注入提供 Messaging 实例前置条件是把 AngularFire 添加进项目ng add angular/fire该命令会安装 AngularFire、Firebase SDK并将provideFirebaseApp(...)以及你选中的各功能 provider 写入应用配置如app.config.tsFirebase 配置会以内联方式写入不创建环境文件详见 docs/install-and-setup.md。随后在应用的app.config.ts中提供 Cloud Messaging 实例import { ApplicationConfig } from angular/core; import { provideFirebaseApp, initializeApp } from angular/fire/app; import { provideMessaging, getMessaging } from angular/fire/messaging; export const appConfig: ApplicationConfig { providers: [ provideFirebaseApp(() initializeApp({ ... })), provideMessaging(() getMessaging()), ... ], ... }接着把Messaging注入到组件中import { Component, inject} from angular/core; import { Messaging } from angular/fire/messaging; Component({ ... }) export class AppComponent { private messaging inject(Messaging); ... }provideMessaging 的底层行为从源码看src/messaging/messaging.module.tsprovideMessaging(fn, ...deps)返回EnvironmentProviders其中默认实例工厂defaultMessagingInstanceFactory会在服务端isPlatformServer(platformId)为真时返回null从而避免在 SSR 环境下创建无法工作的 Messaging 实例客户端侧则通过ɵgetDefaultInstanceOf从已提供的实例中取出默认实例。同时它还会调用registerVersion(angularfire, VERSION.full, fcm)向 Firebase 注册版本信息。Messaging本身是一个接口继承firebase/messaging的Messaging、并用构造器返回底层实例的轻量包装类见 src/messaging/messaging.ts。模块还导出了MessagingInstances与messagingInstance$每 300ms 轮询一次所有已注册 Messaging 实例并去重用于多实例场景。测试 src/messaging/messaging.spec.ts 验证了Messaging可注入且注入结果与provideMessaging提供的实例一致在isSupported返回 false 的环境下则为null。创建 Firebase Messaging Service WorkerFirebase Messaging 由两部分组成Service Worker 与 DOM API。AngularFire Messaging 负责 DOM 侧的请求权限、注册应用实例、监听注册/注销状态变化以及订阅消息而要真正接收通知必须搭建 Service Worker。具体搭建细节以 Firebase 官方客户端文档 为准。在 src/assets 下创建 firebase-messaging-sw.js/* Replace firebase-version with the firebase version in your package.json. The service * worker and your application have to load the same version. */ import { initializeApp } from https://www.gstatic.com/firebasejs/firebase-version/firebase-app.js; import { getMessaging } from https://www.gstatic.com/firebasejs/firebase-version/firebase-messaging-sw.js; const firebaseApp initializeApp({ apiKey: , authDomain: , projectId: , storageBucket: , messagingSenderId: , appId: , }); const messaging getMessaging(firebaseApp);两点重要提醒版本必须严格匹配firebase-version要替换为package.json中firebase的实际版本。Service Worker 与应用必须加载同一版本版本不匹配可能导致前台收不到消息。每次升级firebase依赖后都要同步更新该文件兼容版文档 docs/compat/messaging/messaging.md 也特别标注了这一 Warning。多环境适配建议在不同环境开发/生产下使用 Angular 的 file replacements 或 environment 配置来切换此文件。如果你的项目使用 Angular Service Worker需要注意兼容版 API 并非开箱即用Angular 官方 issue 跟踪中可改用 Workbox、手动注册 Angular Service Worker或直接使用上面的 Firebase Messaging Service Worker 方案。注册应用实例register 与 onRegisteredFirebase 已在 firebase 12.18 弃用getToken/deleteToken并将移除应改用register替代getToken配合onRegistered监听注册结果unregister替代deleteToken配合onUnregistered监听注销结果。Firebase 官方客户端指南描述了这套模型并明确要求不要混用新旧两套 API。复制下面的示例前有三点必须先弄清楚先监听、后注册onRegistered必须在register执行前就已处于监听状态这也是示例代码先订阅的原因。否则register会抛出No onRegistered callback handler was provided or registered.自行请求通知权限应在调用register之前请求权限如示例所做。否则register会在 AngularFire 包裹的调用内部代为弹出权限请求导致客户端应用在对话框关闭前一直处于 unstable 状态——这会延迟 Angular 事件重放与服务端渲染 DOM 的清理并在十秒后打印一条仅开发期可见的警告。先主动请求权限即可完全避免该行为可能在未来的版本中改变。标识符通过回调而非返回值送达register不直接返回 installation ID且每当其变化时回调会再次触发所以应从回调内部保存它而不是在启动时只保存一次。示例一个完整的 Messaging Service下面是一个可复制的FcmService完整实现import { EnvironmentInjector, Injectable, inject, runInInjectionContext } from angular/core; import { Messaging, MessagePayload, onMessage, onRegistered, onUnregistered, register, unregister } from angular/fire/messaging; import { Observable, tap } from rxjs; Injectable({ providedIn: root }) export class FcmService { private readonly injector inject(EnvironmentInjector); /* onMessage converted to an observable. Returns the unsubscribe function returned by * onMessage to stop the listener when the last subscriber unsubscribes. */ message$ new ObservableMessagePayload( subscriber onMessage(this.msg, (msg) subscriber.next(msg)) ).pipe(tap((msg) console.log(My Firebase Cloud Message, msg))); constructor(private msg: Messaging) { // Set listeners before calling register to avoid throwing. this.listenForRegistrationChanges(); this.registerForMessages(); } private listenForRegistrationChanges() { onRegistered(this.msg, (installationId) { /* This is a good place to store it in your database for each user. * This callback fires whenever installationId changes. */ console.log(my installation id, installationId); }); onUnregistered(this.msg, (installationId) { // Drop it from your database. Sending messages to an unregistered ID results in a 404. console.log(no longer registered, installationId); }); } private async registerForMessages() { /* Request notification permission before calling register, otherwise * register holds the app unstable until the user answers. */ if ( Notification.permission default await Notification.requestPermission() ! granted ) { return; } // Register the service worker. const serviceWorkerRegistration await navigator.serviceWorker .register(/assets/firebase-messaging-sw.js, { type: module }); /* Run register inside an injection context. Outside one AngularFire cannot wrap it, and * warns. See zones.md for what wrapping adds. */ runInInjectionContext(this.injector, () register(this.msg, { vapidKey: an optional public VAPID key you generate for your Firebase project, serviceWorkerRegistration, }).catch((error) console.error(could not register for messages, error)) ); } // Called from your app, for example when a user turns notifications off. async unregister() { // This calls the imported unregister, not this method. Class methods are not in lexical scope. await unregister(this.msg); } }这个示例中的几个关键设计点值得展开监听先于注册构造函数中先调用listenForRegistrationChanges()再调用registerForMessages()正是为了避免先注册后监听导致的No onRegistered callback handler was provided or registered.错误。权限请求前置仅在Notification.permission default时请求权限若用户拒绝则直接返回不继续注册。注入上下文register放在runInInjectionContext(this.injector, ...)中执行。AngularFire 的 Zone 包装机制详见 docs/zones.md需要依赖注入环境才能包裹 Firebase API 调用在异步回调等上下文已失效的位置直接调用AngularFire 只能发出警告并放弃包装可能造成应用不稳定、变更检测与 SSR 等待异常。unregister的命名遮蔽类方法unregister()与导入的unregister同名但方法体内的await unregister(this.msg)引用的仍是导入的函数类方法不在词法作用域内注释对此有明确说明。Zone 包装与 firebase.ts 的 API 层从 src/messaging/firebase.ts 可以看到angular/fire/messaging重新导出了firebase/messaging的全部符号并对关键 API 做了ɵzoneWrap包装onMessage、onRegistered、onUnregistered、isSupported不视为阻塞调用false而getToken、deleteToken、register、unregister、getMessaging则被标记为会保持应用 unstabletrue的调用。这正是文档中register 会把客户端应用 hold 住直到权限对话框关闭这一行为的技术根源。测试与发送通知方式一Firebase 控制台发送测试通知在 Firebase 控制台的Engage Messaging New Campaign Notifications中可以直接点击发送测试消息快速验证端到端链路是否打通。方式二通过 Cloud Functions 编程式发送Firebase 允许通过 Cloud Functions 编程式发送通知。下面是一个极简的 Node 示例。注意其token字段在迁移期内仍接受 Firebase Installation ID因此无论你是用旧getToken还是新register注册的都适用Firebase Admin SDK 的发送指南提供了专用的fid字段作为后续迁移目标。export const sendTestMessage onRequest(async (_, res) { try { const message { notification: { title: Test Title, body: Test Body, }, token: your token here, you can store these and retreive as you please, }; await admin.messaging().send(message); res.sendStatus(200); } catch (error) { console.error(error); res.sendStatus(500); } });下面是一个更贴近真实业务的示例监听评论集合的新文档给帖子作者推送通知同时把通知写入 Firestore 缓存方便用户在应用内点击查看exports.onPostReply onDocumentCreated(comments/{commentId}, async (event) { if (!event) throw new Error(No event found for document creation); const snapshot event.data; if (!snapshot) { throw new Error(No data associated with the event); } const data snapshot.data(); if (!data.postId) { throw new Error(No post ID found); } const postRef await firestore.collection(posts).doc(data.postId).get(); const postData postRef.data(); if (!postData) { throw new Error(No postData found); } // userUid will be the post authors id. const {userUid} postData; if (!userUid) { throw new Error( Could not find the userUid for the post author for post reply ); } const messageForNotification { title: You have a new reply on your post, body: , }; await createNotificationAndCache(messageForNotification, userUid); }); // If you want to cache notifications a number of times, abstracting this // to a function can bring a lot of value. interface NotificationProps { title: string; body: string; } async function createNotificationAndCache( notificationProps: NotificationProps, userAuthUid: string) { const userRef await firestore.collection(users).where(authUid, , userAuthUid).get(); const userData userRef.docs[0].data(); const promises: Promiseany[] []; // This sample application has seperate fcm tokens for web and mobile if (userData.mobileToken) { const message { notification: notificationProps, token: userData.mobileToken, }; const promise admin.messaging().send(message); promises.push(promise); } if (userData.webToken) { const message { notification: notificationProps, token: userData.webToken, }; const promise admin.messaging().send(message); promises.push(promise); } const notificationCacheValue { userAuthUid: userAuthUid, tokenTitle: notificationProps.title, tokenBody: notificationProps.body, isActive: true, // This determines whether a notification has been seen }; promises.push( firestore.collection(notificationCache).add(notificationCacheValue)); await Promise.all(promises); }发送通知的关键设计原则服务端发送、客户端只注册发送通知必须调用服务端接口。你可以直接用 HTTP 调用也可以在事件触发时用 Cloud Function 发送。Cloud Function 触发器是更理想的选择因为它拥有受信任的数据库访问权限可以安全地查找 token 并发送给正确的用户。保护 HTTP 发送接口如果通过 HTTP 请求发送推送必须保护该 API 调用通常用 Firebase Auth UID 鉴权服务端用 Firebase Admin SDK 校验 UID 后才允许获取用户的推送 ID。令牌与用户关联用户授予权限后应把 token 存入 Realtime Database 或 Cloud Firestore并与唯一标识如 Firebase Auth UID关联之后创建 Cloud Function 触发器在业务事件发生时按 UID 查 token 再推送。注销即删除onUnregistered回调中应从数据库移除该 Installation ID——向已注销的 ID 发送消息会得到 404。分离 web/mobile token示例中用户文档分别存webToken与mobileToken适用于同一用户在 Web 与移动端各有独立 FCM token 的场景。通知缓存notificationCache集合配合isActive字段可记录通知是否已被查看实现点击跳转的应用内通知中心体验。兼容版 API 的参考对照如果你的项目仍在使用旧式 NgModule 兼容 APIangular/fire/compat/messaging其对应文档见 docs/compat/messaging/messaging.md。兼容版以AngularFireMessagingModuleAngularFireMessaging服务形式提供requestPermission、getToken、tokenChanges、messages、requestToken、deleteToken等 Observable 属性实现见 src/compat/messaging/messaging.ts。其核心思路与新 API 一致先搭建 Service Worker、再请求权限、获取 token 并保存到服务端、订阅前台消息区别在于兼容版通过 RxJS Observable 串联各步骤且需在angular.json的assets中显式配置firebase-messaging-sw.js与manifest.json的拷贝。AngularFire 已全面转向新的 tree-shakable API新项目应直接采用本文的provideMessaging方案。总结完整的 FCM 接入闭环包含四个环节搭建 Service Worker版本与应用严格一致、注册实例先onRegistered再register权限请求前置register在注入上下文中执行、保存与同步 token在onRegistered/onUnregistered回调中写入/删除数据库记录、服务端发送Cloud Functions 中按 UID 查 token 推送并缓存通知供应用内查看。遵循新旧 API 不混用、先监听后注册、先权限后注册这三个原则就能避开 FCM 接入中最常见的坑。赞分享后端【免费下载链接】angularfireAngular Firebase ❤️项目地址https://gitcode.com/gh_mirrors/an/angularfire点击查看免费下载相关推荐SWE-RL异步推理架构OpenAIClient并发请求与指数退避重试实现SWE RL异步推理架构OpenAIClient并发请求与指数退避重试实现 SWE RL异步推理架构是开源项目 SWE RLNeurIPS25 官方代码库为什么这份system-design-notes值得收藏28章系统设计面试笔记全览为什么这份system design notes值得收藏28章系统设计面试笔记全览 system design notes 是一份基于《System D文档教程后端iOS应用Firebase Cloud Messaging推送通知完整实现指南iOS应用Firebase Cloud Messaging推送通知完整实现指南 Firebase Cloud MessagingFCM是Google提供的跨移动开发后端认证鉴权上一篇OctoPrint打印质量优化终极指南提升3D打印成功率的10个技巧下一篇iOS文本性能分析工具TTTAttributedLabel优化辅助创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
微前端大仓中的跨技术栈微模块热重载:基于 Vite 与 ESM 的秒级极速 HMR 微前端大仓中的跨技术栈微模块热重载:基于 Vite 与 ESM 的秒级极速 HMR在大型微前端与 Monorepo 代码大仓的日常本地开发中,严重摧毁工程师“编码心流(Coding Flow)”的最主要元凶莫过于**“本地联调与模块热重载(HMR,… · 2026/9/27 8:47:49
Yao SUI 国际化(i18n)完整指南:翻译标记、语言包目录与 locale 检测机制 Agent 框架后端低代码RAG 【免费下载链接】yao ✨ All your agents and workspaces in one place, on every device you own. Track tasks on a board, accessible from desktop, mobile, browser, or API. Self-hosted. 项目地址: https://gitcode.com/gh_mirrors/… · 2026/9/27 8:47:43
架构决策记录(ADR)在大型分布式系统重构中的落地 架构决策记录(ADR)在大型分布式系统重构中的落地在大型分布式系统演进的过程中,每一个接手遗留系统的研发人员都会经历这种时刻:看到一段极其诡异的代码逻辑或架构选型,去问老员工,老员工说“这是前年某某架… · 2026/9/27 8:47:43
《创业之路》-965-华夏综合神佛仙圣等级体系 华夏综合神佛仙圣等级体系说明:上古神话、道教、佛教、儒教、《封神演义》、《西游记》分属不同来源,原本不存在统一世界观。下文属于文化整合构建,并非单一原著设定,剔除现代洪荒网文(无创世元灵)。 整体层… · 2026/9/27 9:32:55
一文搞懂专门学设计的网站:3步搞定性能与美观 一文搞懂专门学设计的网站:3步搞定性能与美观 模板网站太丑不够用?很多项目经理在交付时发现,套皮出来的页面像“大众脸”,客户一眼看穿没诚意,验收卡壳、返工频繁。专门学设计的网站,不是堆砌炫酷动效,而是用规范把“好看”变成可复制的工程标准。本… · 2026/9/27 9:32:55
计及需求侧响应日前、日内两阶段鲁棒备用优化附Matlab代码 ✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、算法改进、程序设计科研仿真。🍎 往期回顾关注个人主页:完整代码获取 定制创新 论文复现私信🍊个人信条:做科研,… · 2026/9/27 9:32:43
第243篇_民宿短租平台房源与评价采集 【Python爬虫实战】第243篇:房源表和评价表一起拉——民宿短租平台房源信息与用户评价全量抓取实战 所属专栏:【Python爬虫实战】从零到企业级爬虫工程师(CSDN 付费专栏) 本篇篇目:第 243 篇(垂直行业数据采集专题) 难度等级:中级,双表关联采集 阅读时长:约 35 分钟(… · 2026/9/27 9:32:43
rtl_433 JSON 数据输出格式详解:字段规范、单位转换与消息完整性校验 物联网 【免费下载链接】rtl_433 Program to decode radio transmissions from devices on the ISM bands (and other frequencies) 项目地址: https://gitcode.com/gh_mirrors/rt/rtl_433 点击查看 免费下载 导读
rtl_433 是一款用于解码 ISM 频段(以… · 2026/9/27 9:32:42
NodeMCU file_lfs 模块实战:将任意文件嵌入 Lua Flash Store 并透明读写 物联网嵌入式 【免费下载链接】nodemcu-firmware Lua based interactive firmware for ESP8266, ESP8285 and ESP32 项目地址: https://gitcode.com/gh_mirrors/no/nodemcu-firmware 点击查看 免费下载 本指南围绕 NodeMCU 固件仓库中的 file_lfs 模块文档 展开&am… · 2026/9/27 9:32:36
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01