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

Flutter聊天APP Firebase云函数发定向通知报错求助(无JS基础)

问题排查与解决

错误原因解析

  • 云函数逻辑完全错误:不能在HTTPS Callable函数内部定义Firestore触发器(onWrite),触发器是部署阶段注册的,无法在运行时动态创建。
  • admin.firestore().collection("userToken").doc(friendPhone).get()是异步操作,未加await就调用userDoc.data()会拿到undefined;若friendPhone为空(前端传参错误),会直接触发"路径无效"的报错。
  • 前端调用云函数时,friendPhone可能为空字符串,导致传入doc()的参数不符合Firestore路径要求。

正确实现步骤

1. 重构云函数逻辑(index.js)

改成Firestore触发器,当消息写入时自动触发推送,替代原有的HTTPS Callable错误逻辑:

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

admin.initializeApp();

// 修正拼写错误:messegeId → messages,确保路径匹配
exports.sendNotification = functions.firestore
  .document("chats/{chatId}/messages/{messageId}")
  .onCreate(async (snap, context) => {
    // 获取刚写入的消息数据
    const messageData = snap.data();
    if (!messageData) return null;

    // 从消息数据中提取必要参数(需和前端写入字段对应)
    const friendPhone = messageData.friendPhone;
    const title = messageData.title;
    const body = messageData.body;

    // 参数校验,避免空值触发错误
    if (!friendPhone || !title || !body) {
      console.log("缺少必要参数");
      return null;
    }

    // 异步获取好友的设备Token
    const userDoc = await admin.firestore().collection("userToken").doc(friendPhone).get();
    if (!userDoc.exists) {
      console.log("未找到好友的Token记录");
      return null;
    }

    const deviceToken = userDoc.data().token;
    if (!deviceToken) {
      console.log("好友未绑定设备Token");
      return null;
    }

    // 构造推送内容
    const payload = {
      notification: {
        title: title,
        body: body,
        clickAction: "FLUTTER_NOTIFICATION_CLICK"
      }
    };

    // 发送推送通知
    try {
      await admin.messaging().sendToDevice(deviceToken, payload);
      console.log("推送发送成功");
      return null;
    } catch (error) {
      console.error("推送发送失败:", error);
      return null;
    }
  });

2. 修正前端消息写入逻辑

无需调用HTTPS Callable,直接写入Firestore即可触发云函数:

Future<void> writeMessage({
  String? message,
  String? title,
  String? friendPhone,
  String? currentUserPhone,
}) async {
  // 生成唯一聊天ID(避免重复,用两个手机号排序拼接)
  List<String> phones = [currentUserPhone!, friendPhone!];
  phones.sort();
  String chatId = phones.join("_");

  // 写入消息到Firestore
  await FirebaseFirestore.instance
      .collection("chats")
      .doc(chatId)
      .collection("messages")
      .add({
    "title": title,
    "body": message,
    "friendPhone": friendPhone,
    "senderPhone": currentUserPhone,
    "timestamp": FieldValue.serverTimestamp(),
  });
}

3. 前端参数校验

确保调用writeMessage时参数不为空:

// 发送按钮点击事件示例
onPressed: () {
  if (_friendPhoneController.text.isEmpty || _messageController.text.isEmpty) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("请输入好友手机号和消息内容")),
    );
    return;
  }
  writeMessage(
    message: _messageController.text,
    title: "来自${userphone}的消息",
    friendPhone: _friendPhoneController.text,
    currentUserPhone: userphone,
  );
},

4. 部署云函数

在终端执行部署命令:

firebase deploy --only functions:sendNotification

其他注意事项

  • 确保Firebase控制台已开启Cloud Messaging服务,前端已正确配置FCM文件(Android的google-services.json、iOS的GoogleService-Info.plist)。
  • 测试前确认好友的设备Token已正确保存到userToken集合,可在Firebase控制台的Firestore面板查看。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:05:21