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

Flutter接入Firebase Messaging后Node.js云函数推送无响应如何解决

问题排查与修复步骤

1 先排查云函数执行错误

  • 打开Firebase控制台的云函数日志页,查看sendPush函数执行时的报错信息,调用次数正常仅代表触发成功,不代表FCM推送请求发送成功
  • 确认Firestore的notifications集合中存储的token字段值,和你测试设备运行时Flutter控制台打印的token完全一致,无效/过期/错误的token都会导致推送失败但云函数触发计数仍会增加
  • 给FCM发送逻辑添加错误捕获,把错误输出到日志方便定位,修改后的云函数代码如下:
const functions= require("firebase-functions");
const admin =require("firebase-admin");
admin.initializeApp(); 

exports.sendPush = functions.firestore.document('notifications/{notificationId}').onCreate(async (snap, context)=>{
    const data = snap.data();
    const chauffeur = data.chauffeur;
    const date_reception = data.date_reception;
    const send_name = data.send_name;
    const token = data.token;

    console.log('chauffeur:' + chauffeur);
    console.log('date_reception:' + date_reception);
    console.log('send_name:' + send_name);
    console.log('token:' + token);

    const payload = {
       notification:{
            title: 'New message',
            body: 'Message reçu de ' + chauffeur,
            sound: "default",
        },
        data:{
            'chauffeur':chauffeur,
            'date_reception': date_reception,
            'send_name': send_name,
        },
        // 新增Android/iOS优先级配置,确保推送能被系统正常分发
        android: {
            priority: 'high',
            notification: {
                channelId: 'default_channel', // 和客户端创建的通道ID保持一致
                sound: 'default'
            }
        },
        apns: {
            payload: {
                aps: {
                    sound: 'default',
                    contentAvailable: true
                }
            }
        }
    }
    try {
        const response = await admin.messaging().sendToDevice(token, payload);
        console.log('FCM发送结果:', JSON.stringify(response));
        // 打印失败原因,方便排查token相关问题
        response.results.forEach((result, index) => {
            const error = result.error;
            if (error) {
                console.error('推送失败, 错误原因:', error.code);
            }
        });
        return response;
    } catch (e) {
        console.error('发送FCM出错:', e);
        return null;
    }
});

2 修复Flutter端配置问题

Firebase控制台发送测试通知正常,是因为控制台会自动创建默认通知通道,而自行发送的通知需要主动适配Android系统要求:

  • Android 8.0及以上系统需要主动创建通知通道,Android 13及以上需要主动申请通知权限,修改后的Flutter端代码如下:
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

Future<void> _messageHandler(RemoteMessage message) async {
  print('background message ${message.notification?.body}');
}

// 全局通知通道实例
const AndroidNotificationChannel channel = AndroidNotificationChannel(
  'default_channel', // 和云函数里的channelId保持一致
  '默认通知',
  description: '应用推送通知通道',
  importance: Importance.high,
);

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_messageHandler);
  
  // 初始化本地通知,创建通知通道
  await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel);
  
  // 申请通知权限(Android 13+ 必需配置)
  await FirebaseMessaging.instance.requestPermission(
    alert: true,
    badge: true,
    sound: true,
  );
  
  // 设置前台通知展示规则
  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,
  );
  
  runApp(const MessagingTutorial());
}

class MessagingTutorial extends StatelessWidget {
  static const String idScreen = "note";

  const MessagingTutorial({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Firebase Messaging',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Firebase Messaging'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title}) : super(key: key);

  final String? title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late FirebaseMessaging messaging;
  String? notificationText;
  @override
  void initState() {
    super.initState();
    messaging = FirebaseMessaging.instance;
    messaging.getToken().then((value) {
      print('设备token: $value');
    });
    FirebaseMessaging.onMessage.listen((RemoteMessage event) {
      RemoteNotification? notification = event.notification;
      AndroidNotification? androidNotification = event.notification?.android;
      print("message recieved");
      print(event.notification?.body);
      print(event.data.values);
      
      // 前台收到通知时主动弹出
      if (notification != null && androidNotification != null) {
        flutterLocalNotificationsPlugin.show(
          notification.hashCode,
          notification.title,
          notification.body,
          NotificationDetails(
            android: AndroidNotificationDetails(
              channel.id,
              channel.name,
              channelDescription: channel.description,
              icon: '@mipmap/ic_launcher', // 替换为你应用的图标名
            ),
          ),
        );
      }
      
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Text("Notification ${event.data['title'] ?? '新消息'}"),
              content: Text(event.notification?.body ?? ''),
              actions: [
                Row(children: [
                  TextButton(
                    child: const Text("Annuler"),
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                  ),
                  TextButton(
                    child: const Text("Ok"),
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                  )
                ])
              ],
            );
          });
    });
    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      print('Message clicked!');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
      ),
      body: const Center(child: Text("Messaging Tutorial")),
    );
  }
}

3 补充检查项

  • 确认你的android/app/src/main/AndroidManifest.xml的application节点下已经添加了默认通知通道配置:
<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="default_channel" />
  • 确认测试设备没有关闭应用的通知权限,没有开启省电模式拦截推送
  • 如果是iOS设备,确认你已经在Xcode中开启了Push Notifications和Background Modes下的Remote notifications能力

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:09:03