基于Node.js的Flutter多商家应用FCM通知功能实现咨询
实现Flutter+Node.js多商家应用的管理员消息推送通知方案
一、核心选型:Firebase Cloud Messaging(FCM)
FCM是跨平台推送的首选方案,支持Flutter前端和Node.js后端快速集成,无需自建推送服务器,自带离线缓存、设备Token管理等功能,完全适配你的需求场景。
二、Node.js后端实现
1. 集成FCM Admin SDK
首先安装依赖包:
npm install firebase-admin
用Firebase控制台生成的服务账号密钥初始化SDK(建议放在项目配置目录,不要提交到版本控制):
const admin = require('firebase-admin'); const serviceAccount = require('./path/to/service-account-key.json'); // 全局初始化,项目启动时执行一次 admin.initializeApp({ credential: admin.credential.cert(serviceAccount) });
2. 存储用户FCM Token
Flutter端用户登录后,会将设备的FCM Token上传到后端,你需要在用户表中新增fcm_token字段,同时保留premium_status字段(标记是否为付费用户)用于后续校验。
3. 发送消息时触发推送
在管理员发送聊天消息的接口中,添加推送逻辑:
- 校验当前操作者是
super_admin(通过登录态验证,比如JWT token解析) - 查询接收用户的Premium状态和FCM Token
- 调用FCM API发送通知,携带聊天会话ID用于前端跳转
示例代码:
const UserModel = require('./models/User'); const ChatMessageModel = require('./models/ChatMessage'); // 封装推送函数 async function sendAdminChatNotification(userId, messageContent, chatId) { // 校验用户是否为活跃Premium用户 const user = await UserModel.findById(userId); if (!user || user.premium_status !== 'active') return; const fcmMessage = { notification: { title: '管理员消息', body: messageContent }, token: user.fcm_token, data: { type: 'admin_chat', chat_id: chatId // 用于前端跳转至对应聊天页面 } }; try { await admin.messaging().send(fcmMessage); console.log(`通知已发送至用户 ${userId}`); } catch (err) { console.error(`推送失败:${err.message}`); // 可选:记录失败日志,后续重试或清理无效Token if (err.code === 'messaging/invalid-registration-token') { await UserModel.findByIdAndUpdate(userId, { fcm_token: null }); } } } // 管理员发送消息接口 app.post('/api/admin/send-chat', async (req, res) => { const { receiver_id, content } = req.body; const adminId = req.user.id; // 从JWT解析获取当前管理员ID // 1. 保存聊天消息到数据库 const chatMessage = await ChatMessageModel.create({ sender: adminId, receiver: receiver_id, content, type: 'admin_message' }); // 2. 触发推送通知 await sendAdminChatNotification(receiver_id, content, chatMessage._id.toString()); res.status(200).json({ success: true, message: '消息发送成功' }); });
4. 处理无效Token
FCM会返回messaging/invalid-registration-token错误,此时需要将用户表中对应的Token置空,避免后续重复推送失败。
三、Flutter前端实现
1. 集成FCM与本地通知插件
添加依赖到pubspec.yaml:
dependencies: firebase_messaging: ^14.6.1 flutter_local_notifications: ^16.1.0 http: ^1.1.0
配置Android和iOS的FCM凭证(GoogleService-Info.plist、google-services.json),按官方配置流程完成基础设置即可。
2. 获取并上传FCM Token
用户登录成功后,获取设备Token并上传到后端:
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:http/http.dart' as http; Future<void> uploadFcmToken(String userId) async { String? token = await FirebaseMessaging.instance.getToken(); if (token == null) return; final response = await http.post( Uri.parse('https://your-api-domain.com/api/user/update-fcm-token'), body: {'user_id': userId, 'fcm_token': token}, ); if (response.statusCode != 200) { // 处理上传失败,比如重试逻辑 print('FCM Token上传失败'); } }
3. 处理通知接收与跳转
初始化通知监听,处理前台、后台及杀死状态下的通知:
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter/material.dart'; import 'dart:convert'; final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); void initNotificationListeners(BuildContext context) async { // 初始化本地通知配置 const AndroidInitializationSettings androidInit = AndroidInitializationSettings('@mipmap/ic_launcher'); const IOSInitializationSettings iosInit = IOSInitializationSettings(); const InitializationSettings initSettings = InitializationSettings(android: androidInit, iOS: iosInit); await _notificationsPlugin.initialize( initSettings, onSelectNotification: (String? payload) async { // 点击通知跳转聊天页面 if (payload != null) { final data = jsonDecode(payload); if (data['type'] == 'admin_chat') { Navigator.push( context, MaterialPageRoute(builder: (_) => ChatScreen(chatId: data['chat_id'])), ); } } }, ); // 前台接收通知 FirebaseMessaging.onMessage.listen((RemoteMessage message) { final notification = message.notification; final android = message.notification?.android; if (notification != null && android != null) { _notificationsPlugin.show( notification.hashCode, notification.title, notification.body, NotificationDetails( android: AndroidNotificationDetails( 'admin_chat_channel', '管理员消息频道', importance: Importance.max, priority: Priority.high, icon: android.smallIcon, ), ), payload: jsonEncode(message.data), ); } }); // 后台点击通知 FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { final data = message.data; if (data['type'] == 'admin_chat') { Navigator.push( context, MaterialPageRoute(builder: (_) => ChatScreen(chatId: data['chat_id'])), ); } }); // 杀死状态下点击通知(需配置Firebase后台消息处理) RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) { final data = initialMessage.data; if (data['type'] == 'admin_chat') { Navigator.push( context, MaterialPageRoute(builder: (_) => ChatScreen(chatId: data['chat_id'])), ); } } }
4. 申请通知权限
在App启动时申请iOS和Android 13+的通知权限:
Future<void> requestNotificationPermission() async { NotificationSettings settings = await FirebaseMessaging.instance.requestPermission( alert: true, badge: true, sound: true, ); if (settings.authorizationStatus != AuthorizationStatus.authorized) { // 提示用户开启通知权限 print('用户未授权通知权限'); } }
四、权限校验强化
- 后端接口必须校验
super_admin身份:通过JWT token解析角色字段,非管理员直接拒绝请求。 - 推送前严格校验用户Premium状态:仅给
premium_status为active的用户发送通知。 - Flutter端进入聊天页面时二次校验:如果用户Premium已过期,跳转至付费订阅页面。
五、优化建议
- 批量推送:若需给多个Premium用户发消息,使用FCM的
sendMulticast接口,减少请求开销。 - 推送记录:在数据库中新增
notification_logs表,记录推送状态、用户ID、消息内容,方便管理员追溯。 - 自定义通知频道:针对不同类型的通知(如系统公告、管理员消息)创建不同的Android通知频道,用户可自主设置通知优先级。
- 离线消息同步:用户上线后,前端主动拉取未读的管理员消息,补充推送可能遗漏的内容。
内容的提问来源于stack exchange,提问作者Nouman Rafiq
相关产品推荐
相关产品推荐

