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

Firebase基于主题的推送通知重复问题排查求助

生产环境Firebase主题推送重复通知排查问题

背景与实现方案

我们采用Firebase Functions(TypeScript)实现即时触发与定时触发的推送通知,随着用户规模增长,切换为基于主题(Topic)的推送方案,移动端负责主题的创建、订阅与退订逻辑。

关键代码片段

1. 移动端主题订阅/退订逻辑

if (name !== undefined) {
  const nameLower = name.toLowerCase()
  if (countryName) {
    isSubscribe ? await messaging().subscribeToTopic(nameLower) : await messaging().unsubscribeFromTopic(nameLower)
 }
}

if (platform) {
 isSubscribe ? await messaging().subscribeToTopic(platform) : await messaging().unsubscribeFromTopic(platform)
}

mIds?.forEach(async element => {
 if (element) {
   isSubscribe ? await messaging().subscribeToTopic(element) : await messaging().unsubscribeFromTopic(element)
 }
});

arrIds?.forEach(async element => {
 const createTopic = `${element?.tId}-${element?.rId}`
 if (createTopic) {
   isSubscribe ? await messaging().subscribeToTopic(createTopic) : await messaging().unsubscribeFromTopic(createTopic)
 }
});

2. 移动端通知处理(NotificationCenter.ts)

useEffect(() => {
  // 前台通知展示
  const unsubscribe = messaging().onMessage((remoteMessage) => {
  if (remoteMessage.notification) {
    showMessage({
      message: remoteMessage.notification.title,
      description: remoteMessage.notification.body,
      type: "success",
      duration: 3000,
      statusBarHeight: StatusBar.currentHeight,
      onPress: () => {
        remoteMessage?.data?.Id && details(remoteMessage?.data?.Id)
      },
     })
    }
  })

  return () => {
    unsubscribe()
  }
}, [])


useEffect(() => {
 // iOS角标清零
 return notifee.onForegroundEvent(({ type, detail }) => {
  switch (type) {
    case EventType.PRESS:
      notifee.setBadgeCount(0)
      detail.notification?.data && details(detail.notification?.data?.Id as string)
      break
   }
 })
}, [])

useEffect(() => {
// 应用冷启动时处理初始通知
 messaging()
  .getInitialNotification()
  .then((remoteMessage) => {
    if (remoteMessage) {
      remoteMessage.data.Id && details(remoteMessage.data.Id)
    }
  })
}, [])

useEffect(() => {
 // 应用后台时点击通知打开应用的处理
 messaging().onNotificationOpenedApp((remoteMessage) => {
  remoteMessage.data.Id && details(remoteMessage.data.Id)
 })
}, [])

const details = (Id: string) => {
 // 详情页跳转逻辑
 client.notificationDetails(true)
 navigate("detailsScreen", { Id })
}

3. 云函数动态构建推送条件并发送通知

// 动态构建推送条件
if (global.length > 0) {
  condition = `'${data?.IdString}' in topics`;
} else {
  condition = fireb.docs.reduce(
    (cnd, data, i) =>
      `${cnd}${i > 0 ? ' || ' : ''}'${details?.Id[0]}-${
        data.data().refId
      }' in topics`,
    '',
  );
  // 示例条件:"xxxxxxx-xxxxx-<firebase doc id>' in topics || 'xxxxxxx-xxxxx-<firebase doc id>' in topics"
}

const message = {
 notification: {
  title: `${name} - ${title}`,
  body: details?.heading?.body,
 },
 apns: {
  payload: {
    aps: {
      sound: 'default',
      badge: 1,
    },
  },
 },
 data: {refId: `${data?.Id}`},
 condition: condition, // 动态生成的条件
};
// 发送主题推送
const response = await admin.messaging().send(message);

问题现象

测试与预发布环境(用户及主题数量较少)未出现重复通知问题,但生产环境(订阅用户规模1k-10k)偶尔出现重复通知:今日推送的10条通知中,有2条出现重复,一条重复4次,另一条重复2次。已确认云函数日志仅触发一次,无重复执行记录。

求助需求

排查代码中是否存在导致重复通知的bug,或是Firebase Admin SDK层面的问题?

内容的提问来源于stack exchange,提问作者Fahry Mohammed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 19:37:43