Flutter Firebase Messaging实现点击推送跳转指定页面
Flutter Firebase Messaging 实现全场景通知路由跳转
要覆盖前台接收、后台点击、冷启动三种场景的通知路由跳转,核心是解决消息跨组件传递和Context获取的问题,以下是具体实现方案:
1. 全局消息传递工具
定义一个全局的ValueNotifier来跨组件传递通知消息,让主页能实时监听消息变化:
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; // 全局通知消息通知器 final ValueNotifier<RemoteMessage?> notificationMessage = ValueNotifier(null);
2. 改造顶层消息监听
在main函数中,修改onMessage并添加onMessageOpenedApp监听,将消息同步到全局通知器:
void main() async { WidgetsFlutterBinding(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); // 前台接收消息时,同步到全局通知器 FirebaseMessaging.onMessage.listen((RemoteMessage message) { print('Got a message whilst in the foreground!'); print('Message data: ${message.data}'); if (message.notification != null) { print('Message also contained a notification: ${message.notification}'); } // 传递消息到全局通知器 notificationMessage.value = message; }); // 后台点击通知时,同步到全局通知器 FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { print('Message opened from background!'); notificationMessage.value = message; }); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); runApp(const MyApp()); } Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { print("Handling a background message: ${message.messageId}"); }
3. 主页监听消息并实现跳转
在主页的initState中,同时处理冷启动消息和全局通知器的消息变化,调用Navigator完成路由跳转:
import 'package:flutter/material.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override void initState() { super.initState(); // 处理冷启动(APP完全关闭)的消息 _handleInitialMessage(); // 监听全局通知器的消息变化 _listenToNotificationMessages(); } void _handleInitialMessage() async { RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) { _navigateToRoute(initialMessage); } } void _listenToNotificationMessages() { notificationMessage.addListener(() { if (notificationMessage.value != null && mounted) { _navigateToRoute(notificationMessage.value!); // 处理后重置消息,避免重复跳转 notificationMessage.value = null; } }); } void _navigateToRoute(RemoteMessage message) { // 从消息data中取出预设的路由字段(比如你推送时携带的"route"参数) String? targetRoute = message.data['route']; if (targetRoute != null) { Navigator.pushNamed(context, targetRoute); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: const Center(child: Text('Home Page')), ); } }
4. 补充:后台静默接收消息的处理
如果需要处理APP后台运行时接收消息但未点击通知的场景(比如自动跳转),可以用SharedPreferences存储待处理消息,待APP回到前台时检查并跳转:
第一步:修改后台消息处理函数
import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { print("Handling a background message: ${message.messageId}"); // 将消息数据存入SharedPreferences SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString('pending_notification', jsonEncode(message.data)); }
第二步:在主页添加待处理消息检查
@override void initState() { super.initState(); _handleInitialMessage(); _listenToNotificationMessages(); // 检查后台静默接收的待处理消息 _checkPendingNotification(); } void _checkPendingNotification() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? pendingData = prefs.getString('pending_notification'); if (pendingData != null && mounted) { Map<String, dynamic> messageData = jsonDecode(pendingData); String? targetRoute = messageData['route']; if (targetRoute != null) { Navigator.pushNamed(context, targetRoute); // 清除已处理的消息 await prefs.remove('pending_notification'); } } }
内容的提问来源于stack exchange,提问作者Ruder Buster
相关产品推荐
相关产品推荐

