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

Flutter调用Firebase可调用函数发送FCM通知时出现400错误:参数无效(sentBy/sentTo为null)

Flutter调用Firebase可调用函数发送FCM通知时出现400错误:参数无效(sentBy/sentTo为null)

看起来你遇到的问题是函数端检测到sentBy或sentTo为null,但Flutter端明明已经传递了参数且用户已登录。咱们一步步排查解决:

首先,排查sentBy为null的可能原因

context.auth?.uid为null通常意味着Firebase可调用函数没有获取到用户的认证上下文。虽然HttpsCallable默认会自动带上当前登录用户的身份信息,但还是有几个点需要确认:

  • 检查你的Firebase可调用函数是否启用了身份验证:默认情况下,可调用函数要求用户必须登录,但如果你的函数配置了宽松的安全规则(比如允许未认证访问),context.auth会是null。你可以在函数代码里加一行调试日志,看看context.auth的具体内容:
    console.log('Context auth details:', context.auth);
    
  • 确认Flutter端的用户确实处于登录状态:虽然你判断了currentUser != null,但可以额外打印当前用户的UID,确保它不为空:
    print("Current logged-in user UID: ${currentUser.uid}");
    

然后,排查sentTo为null的问题

你说sentTo是设备Token,但函数端接收不到,可能的原因:

  • 检查Flutter端传参的键名是否完全匹配:你的代码里传的是"sentTo",函数里取的是data.sentTo,键名是对的,但可以在函数里打印收到的data对象,确认是否真的收到了这个参数:
    console.log('Received request data:', data);
    
  • 确认Flutter端的sentTo变量确实不为空:你代码里的打印是print('senTo '+sentTo);——这里有个拼写错误(senTo少了一个t),虽然变量本身是sentTo,但建议修正打印语句,确保你看到的是真实的变量值:
    print('sentTo value: $sentTo');
    

还有一个隐藏问题:FCM消息的payload未定义

你的函数代码里直接调用了admin.messaging.sendToDevice(sentTo, payload),但payload变量根本没定义!这会导致后续发送通知时抛出错误,即使前面的参数检查通过了。你需要先定义FCM的消息payload,比如:

const payload = {
  notification: {
    title: "有人戳了你!",
    body: message,
    sound: "default" // 让通知有提示音
  },
  data: {
    // 可选:传递额外数据给客户端
    senderUid: sentBy,
    timestamp: currentTime.toDate().toString()
  }
};

修改后的完整函数代码参考

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

module.exports = async (data,context) => {
  // 调试日志,帮助定位问题
  console.log('Received data:', data);
  console.log('Context auth:', context.auth);

  const sentBy = context.auth?.uid; // 发送者UID
  const sentTo = data.sentTo;       // 接收者的设备Token
  const message = data.message || "Seni dürttü!";
  const currentTime = admin.firestore.Timestamp.now();


  if (!sentBy || !sentTo) { 
    throw new functions.https.HttpsError(
      "invalid-argument",
      `发送者和接收者信息不能为空。sentBy: ${sentBy}, sentTo: ${sentTo}`
    );
  }

  // 定义FCM通知内容
  const payload = {
    notification: {
      title: "新的戳一下通知",
      body: message,
      sound: "default"
    },
    data: {
      sentBy: sentBy,
      timestamp: currentTime.toDate().toString()
    }
  };

  try {
    const response = await admin.messaging.sendToDevice(sentTo, payload);
    console.log('通知发送成功:', response);
    return { success: true, message: "通知已发送" };
  } catch (error) {
    console.error('发送通知失败:', error);
    throw new functions.https.HttpsError("internal", "发送通知失败,请稍后重试", error);
  }
};

修改后的Flutter端代码参考

Future<void> sendPokeNotification(String sentTo) async {
  try {
    final HttpsCallable callable =
        FirebaseFunctions.instance.httpsCallable('sendPoke');

    print('sentTo: $sentTo'); // 确认设备Token不为空
    final currentUser = FirebaseAuth.instance.currentUser;
    if (currentUser == null) {
      throw Exception("用户未登录");
    }

    print("当前登录用户UID: ${currentUser.uid}"); // 确认用户已登录
    final idToken = await currentUser.getIdToken();
    print("用户Token: $idToken");

    final response = await callable.call<String, dynamic>({
      "sentTo": sentTo,
      "message": 'Hi, i poked you!',
    });

    print('函数响应: ${response.data}');
  } catch (e) {
    print('发送戳一下通知错误: $e');
  }
}

按照上面的步骤排查和修改后,应该能解决参数为null的问题,同时修复FCM发送的隐藏错误。记得部署更新后的函数,然后测试看看调试日志里的内容,这样能更精准地定位问题。

备注:内容来源于stack exchange,提问作者Yasin G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:23:00