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
相关产品推荐
相关产品推荐

