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

如何通过Firebase云函数向所有用户推送通知?现有实现遇阻求排查

如何使用Firebase Cloud Messaging向所有用户推送通知?

我之前通过设备的FCM Token,使用admin.messaging().sendToDevice(tokens, payload)方法向特定用户推送通知。现在我尝试向所有用户推送通知,但无法成功。以下是我的实现代码,请问该实现是否正确?若错误,该如何达成需求?

const payload = {
  notification: {
    title: 'Hey! ',
    body: `Check Choice of the day.`,
    sound: 'default',
    icon: '',
    type: 'Editorial',
    badge : '1'
  }
};
return admin.messaging().sendToTopic("News",payload)
.then(function(response){
  console.log('Notification sent successfully:',response);
})
.catch(function(error){
  console.log('Notification sent failed:',error);
});

你的代码问题分析

从语法层面看,这段代码是没问题的,但为什么收不到推送?核心原因是:sendToTopic只能推送给主动订阅了该主题的设备。如果你的用户设备没有在客户端代码里订阅"News"这个主题,自然就收不到你发的通知。

两种实现向所有用户推送的方案

方案1:基于主题推送(推荐)

主题推送是FCM官方推荐的大规模用户推送方式,步骤分为两步:

  1. 在客户端让所有用户设备订阅"News"主题
  2. 服务端用你现在的代码发送主题通知

以下是各平台的客户端订阅代码示例:

  • Android(Kotlin):
FirebaseMessaging.getInstance().subscribeToTopic("News")
    .addOnCompleteListener { task ->
        val msg = if (task.isSuccessful) "Subscribed to News topic" else "Subscribe failed"
        Log.d(TAG, msg)
    }
  • iOS(Swift):
Messaging.messaging().subscribe(toTopic: "News") { error in
    let status = error?.localizedDescription ?? "Successfully subscribed to News topic"
    print(status)
}
  • Web(JavaScript):
messaging.subscribeToTopic('News')
  .then(() => console.log('Subscribed to News topic successfully'))
  .catch(error => console.error('Topic subscription failed:', error));

完成客户端订阅后,你当前的服务端代码就能正常推送给所有订阅了"News"主题的用户了。

方案2:批量发送到所有用户Token(适合小规模用户)

如果不想用主题,你可以先从数据库中收集所有用户的FCM Token,再用sendToDevice批量发送。但要注意:sendToDevice一次最多支持1000个Token,用户量超过这个数的话需要分批处理。

示例代码:

// 第一步:从数据库获取所有有效的FCM Token
const getAllValidTokens = async () => {
  // 这里替换成你的数据库查询逻辑,比如从Firestore的users集合获取
  const userSnapshot = await admin.firestore().collection('users').get();
  // 过滤掉空的或无效的Token
  return userSnapshot.docs
    .map(doc => doc.data().fcmToken)
    .filter(token => token && typeof token === 'string');
};

// 第二步:分批发送通知
const sendNotificationToAllUsers = async () => {
  const payload = {
    notification: {
      title: 'Hey! ',
      body: `Check Choice of the day.`,
      sound: 'default',
      icon: '',
      type: 'Editorial',
      badge : '1'
    }
  };

  const allTokens = await getAllValidTokens();
  const batchSize = 1000; // FCM单次发送上限

  for (let i = 0; i < allTokens.length; i += batchSize) {
    const currentBatch = allTokens.slice(i, i + batchSize);
    try {
      const response = await admin.messaging().sendToDevice(currentBatch, payload);
      console.log(`Batch ${Math.floor(i/batchSize) + 1} sent successfully`, response);

      // 可选:处理无效Token,从数据库中移除
      const invalidTokens = [];
      response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          console.error(`Failed to send to token ${currentBatch[index]}`, error);
          // 标记无效Token(比如过期或未注册的)
          if (['messaging/invalid-registration-token', 'messaging/registration-token-not-registered'].includes(error.code)) {
            invalidTokens.push(currentBatch[index]);
          }
        }
      });

      // 这里可以添加删除无效Token的逻辑
      if (invalidTokens.length > 0) {
        console.log('Removing invalid tokens:', invalidTokens);
        // 示例:从Firestore删除对应Token的用户记录或更新Token字段
        invalidTokens.forEach(token => {
          admin.firestore().collection('users').where('fcmToken', '==', token).get()
            .then(snapshot => snapshot.docs.forEach(doc => doc.ref.update({fcmToken: null})));
        });
      }
    } catch (error) {
      console.error(`Batch ${Math.floor(i/batchSize) + 1} send failed`, error);
    }
  }
};

return sendNotificationToAllUsers();

⚠️ 注意:当用户量很大时,这种方法会消耗更多资源,且容易触发FCM的配额限制,优先选择主题推送更高效稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:35:42