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

Android聊天功能Cloud Function开发问题:推送通知失效需修正

修复Firebase Cloud Function聊天推送通知问题

先看你代码里的几个关键问题,这些是导致推送失败的主要原因:


代码里的核心问题

  1. Admin初始化错误:你把数据库引用直接传给了admin.initializeApp(),这完全不对,Cloud Functions环境下只需要默认初始化即可。
  2. 函数结构语法错误:你把onWrite的回调逻辑错误地嵌套在了admin.initializeApp()的参数里,导致函数根本无法正确注册。
  3. 旧版onWrite语法:你用的是旧版本的event参数,现在Firebase Functions推荐使用change和context来获取数据变化和路径参数。
  4. 未返回异步操作的Promise:sendToDevice之后没有返回Promise,会导致Cloud Function在推送完成前就终止,无法完成推送流程。
  5. 错误处理缺失:没有处理获取用户信息、instanceId失败的情况,也没有处理推送失败的错误日志。

修正后的完整代码

const functions = require('firebase-functions');
const admin = require('firebase-admin');

// 正确初始化Firebase Admin
admin.initializeApp();

// 监听chat_rooms下的写入事件
exports.sendChatNotification = functions.database.ref('/chat_rooms/{pushId}')
  .onWrite(async (change, context) => {
    // 获取最新的消息数据(写入后的数据)
    const message = change.after.val();
    if (!message) {
      // 如果数据被删除,直接返回
      return null;
    }

    const senderUid = message.from;
    const receiverUid = message.to;

    // 发送者和接收者是同一个人,不发送通知
    if (senderUid === receiverUid) {
      console.log('Sender and receiver are the same, skipping notification');
      return null;
    }

    try {
      // 并行获取接收者的instanceId和发送者的用户信息
      const [instanceIdSnapshot, senderUser] = await Promise.all([
        admin.database().ref(`/dokters/${receiverUid}/instanceId`).once('value'),
        admin.auth().getUser(senderUid)
      ]);

      const instanceId = instanceIdSnapshot.val();
      if (!instanceId) {
        console.log(`No instanceId found for receiver ${receiverUid}`);
        return null;
      }

      console.log(`Notifying ${receiverUid} about message: ${message.body} from ${senderUid}`);

      // 构建推送通知 payload
      const payload = {
        notification: {
          title: senderUser.displayName || 'Unknown Sender',
          body: message.body,
          icon: senderUser.photoURL || '',
          click_action: 'FLUTTER_NOTIFICATION_CLICK' // 如果是Flutter项目,需要这个参数(可选)
        },
        // 可选:添加数据字段,方便客户端处理点击事件
        data: {
          senderUid: senderUid,
          message: message.body
        }
      };

      // 发送推送通知,并返回Promise确保函数等待完成
      const response = await admin.messaging().sendToDevice(instanceId, payload);
      console.log('Successfully sent message:', response);

      // 处理推送失败的情况(比如设备未注册)
      const failedTokens = [];
      response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          console.error('Failure sending to token:', instanceId, error);
          // 如果是无效token,可以考虑从数据库删除
          if (error.code === 'messaging/invalid-registration-token' ||
              error.code === 'messaging/registration-token-not-registered') {
            failedTokens.push(instanceIdSnapshot.ref.remove());
          }
        }
      });

      return Promise.all(failedTokens);
    } catch (error) {
      console.error('Error processing notification:', error);
      return null;
    }
  });

关键修改说明

  1. 修正Admin初始化:admin.initializeApp()不需要额外参数,Cloud Functions会自动加载环境配置。
  2. 使用新版onWrite语法:用async/await替代Promise链式调用,代码更易读;通过change.after.val()获取最新数据。
  3. 完善数据校验:检查message是否存在(处理数据删除的情况),检查instanceId是否存在,避免无效推送。
  4. 确保异步操作返回Promise:所有异步操作(数据库查询、获取用户信息、发送推送)都用await处理,确保函数等待操作完成后再结束。
  5. 增强错误处理:用try/catch捕获所有异常,同时处理推送失败的token,比如删除无效的instanceId。
  6. 添加可选数据字段:payload里的data字段可以帮助客户端处理通知点击事件,比如跳转到聊天界面。

额外检查事项

  • 确认接收者的instanceId已经正确保存到/dokters/{receiverUid}/instanceId路径下,注意路径拼写(你代码里写的dokters是正确的,不要和doctors混淆)。
  • 检查Firebase控制台的Functions日志,如果推送失败,日志里会显示具体错误(比如token无效、权限问题)。
  • 确保设备已经获取到FCM token并上传到数据库,且token没有过期。
  • 确认你的Cloud Functions已经部署成功:运行firebase deploy --only functions重新部署。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:18:02