You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Firebase生日APP:如何实现每日FCM个性化生日推送?

问题描述

我正在开发一款基于React Js、Firebase的生日Web应用,支持Firebase登录功能,用户可添加好友生日并查看个性化生日列表。
我需要每日在特定时间通过Firebase Cloud Messaging(FCM)向所有用户发送个性化通知——通知内容要根据Firebase数据库中该用户当天的生日列表生成。试了几种方法都没成功,求可行的实现方案。

已尝试的方法
  1. 仅通过React前端实现通知
    • 缺陷:必须保持应用处于开启状态才能触发,而且移动端的visibilitychange事件无法正常工作。
    • 代码示例:
      let notification
      let interval
      
      document.addEventListener("visibilitychange", () => {
        if (document.visibilityState === "hidden") {
          let date = new Date()
          let dateNumber = date.getDate()
          let monthId = date.getMonth() + 1
          let hours = date.getHours()
          let minutes = date.getMinutes()
          if (hours === 0) {
            let requiredNames = []
            if (allBirthdays.length !== 0) {
              requiredNames = allBirthdays
                .filter((p) => p.monthId == monthId && p.day == dateNumber)
                .map((p) => {
                  return `${p.name}`;
                })
            }
            notification = new Notification(`Today's Birthdays(${dateNumber}-${monthId})`, {
              body: `${requiredNames.length !== 0 ? requiredNames : "No Birthdays"}`,
              icon: logo,
              tag: "Same Time"
            })
          }
          interval = setInterval(() => {
            date = new Date()
            dateNumber = date.getDate()
            monthId = date.getMonth() + 1
            hours = date.getHours()
            minutes = date.getMinutes()
            if (hours === 0 && minutes < 15) {
              let requiredNames = []
              if (allBirthdays.length !== 0) {
                requiredNames = allBirthdays
                  .filter((p) => p.monthId == monthId && p.day == dateNumber)
                  .map((p) => {
                    return `${p.name}`;
                  })
              }
              notification = new Notification(`Today's Birthdays(${dateNumber}-${monthId})`, {
                body: `${requiredNames.length !== 0 ? requiredNames : "No Birthdays"}`,
                icon: logo,
                tag: "Next Interval"
              })
            }
          }, 900000);
        } else {
          if (interval) clearInterval(interval)
          if (notification) notification.close()
        }
      })
      
  2. 查阅视频教程
    • 缺陷:内容仅涉及FCM推送测试,没有覆盖实际落地的个性化定时推送逻辑。
可行实现方案

核心思路

用Firebase Cloud Functions + Firestore + FCM组合实现,前端负责注册FCM令牌并关联用户,后端通过定时任务处理个性化内容并推送。

步骤分解

  1. 前端:存储FCM令牌到Firestore

    • 用户登录后,调用FCM的getToken()获取推送令牌,将令牌与用户ID关联,存入Firestore的users集合(比如在用户文档中添加fcmTokens数组字段)。
    • 监听令牌刷新事件,当FCM令牌更新时,及时同步更新Firestore中的数据,避免推送失败。
  2. Cloud Functions:编写定时触发的推送函数

    • 使用Firebase的定时触发器(比如设置为每天凌晨0点触发),函数核心逻辑:
      1. 获取当前日期的日、月信息。
      2. 遍历所有用户,查询该用户的生日列表,筛选出当天过生日的好友。
      3. 为有当日生日的用户生成个性化通知内容。
      4. 调用FCM API向用户的令牌推送通知。
    • 简化版代码示例:
      const functions = require("firebase-functions");
      const admin = require("firebase-admin");
      admin.initializeApp();
      
      // 每天凌晨0点触发(可配置时区)
      exports.sendDailyBirthdayNotifications = functions.pubsub.schedule('0 0 * * *')
        .timeZone('Asia/Shanghai')
        .onRun(async (context) => {
          const today = new Date();
          const day = today.getDate();
          const month = today.getMonth() + 1;
      
          const usersSnapshot = await admin.firestore().collection('users').get();
          const promises = [];
      
          usersSnapshot.forEach(async (userDoc) => {
            const userId = userDoc.id;
            const fcmTokens = userDoc.data().fcmTokens;
            if (!fcmTokens || fcmTokens.length === 0) return;
      
            // 查询该用户当天的生日记录
            const birthdaysSnapshot = await admin.firestore()
              .collection('users')
              .doc(userId)
              .collection('birthdays')
              .where('day', '==', day)
              .where('monthId', '==', month)
              .get();
      
            const birthdayNames = birthdaysSnapshot.docs.map(doc => doc.data().name);
            if (birthdayNames.length === 0) return;
      
            // 构建通知 payload
            const payload = {
              notification: {
                title: `今日生日(${day}-${month})`,
                body: birthdayNames.join('、'),
                icon: '你的应用图标URL'
              },
              tokens: fcmTokens
            };
      
            // 批量推送通知
            promises.push(admin.messaging().sendMulticast(payload));
          });
      
          return Promise.all(promises);
        });
      
  3. 配置与部署

    • 确保Firebase项目已启用Cloud Functions、Firestore、FCM服务。
    • 安装Firebase CLI,本地运行firebase deploy --only functions部署定时函数。
    • 测试时可临时将触发器改为每分钟触发(* * * * *),验证逻辑正常后改回目标时间。

注意事项

  • 性能优化:用户量较大时,避免一次性遍历所有用户,可分批处理;或提前在Firestore中建立按生日日期索引的集合,减少查询耗时。
  • 错误处理:捕获FCM推送失败的令牌,从Firestore中移除无效令牌,避免后续无效推送。
  • 时区配置:定时触发器的时区要匹配用户所在时区,确保通知在正确时间发送。

内容的提问来源于stack exchange,提问作者AS Tn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 13:05:26