Flutter实现类WhatsApp通知点击分状态(冷/热态)导航
解决方案
核心是通过启动标记+OneSignal冷态通知拦截区分两种状态的导航逻辑,彻底解决闪屏页覆盖目标页的问题。
1. 全局标记定义
先定义全局变量用来标记跳转状态、存储通知参数:
// 标记是否需要跳过闪屏页,仅冷态启动时生效 bool shouldSkipSplash = false; // 存储通知携带的目标页面参数 Map<String, dynamic>? notificationTargetData;
2. 修改main.dart初始化逻辑
在runApp()前完成OneSignal初始化,拦截冷态启动的通知数据:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化OneSignal await OneSignal.initialize("YOUR_APP_ID"); // 处理冷态启动时的通知点击(应用完全关闭后点击通知) final OSNotificationOpenedResult? openedResult = await OneSignal.notificationOpened(); if (openedResult != null) { notificationTargetData = openedResult.notification.additionalData; // 检查是否有目标页面参数,有则标记跳过闪屏 if (notificationTargetData?['target_screen'] != null) { shouldSkipSplash = true; } } runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'App Name', // 根据标记设置初始路由 initialRoute: shouldSkipSplash ? '/target' : '/splash', routes: { '/splash': (context) => const SplashScreen(), '/home': (context) => const HomeScreen(), '/target': (context) => TargetScreen( data: notificationTargetData, ), }, // 处理冷态跳转的返回栈逻辑 onGenerateRoute: (settings) { if (settings.name == '/target' && shouldSkipSplash) { return MaterialPageRoute( builder: (context) => TargetScreen(data: notificationTargetData), settings: settings, ); } return null; }, ); } }
3. 修改SplashScreen的自动跳转逻辑
去掉硬编码的3秒延迟,根据全局标记决定行为:
class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State<SplashScreen> createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { @override void initState() { super.initState(); _handleNavigation(); } void _handleNavigation() { if (!shouldSkipSplash) { // 原逻辑:3秒后跳转到首页 Future.delayed(const Duration(seconds: 3), () { Navigator.pushReplacementNamed(context, '/home'); }); } else { // 跳过闪屏,直接跳目标页,同时保留首页在返回栈 Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (context) => TargetScreen(data: notificationTargetData), ), (route) => route.isFirst, // 返回时回到首页 ); // 重置标记,避免下次启动误触发 shouldSkipSplash = false; } } @override Widget build(BuildContext context) { return const Scaffold( body: Center(child: Text('Splash Screen')), ); } }
4. 热态通知点击处理(完善原有逻辑)
在首页初始化时添加热态通知监听,直接跳转目标页:
class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { @override void initState() { super.initState(); _setupNotificationListener(); } void _setupNotificationListener() { // 前台/后台点击通知时直接跳转 OneSignal.notificationOpenedStream.listen((OSNotificationOpenedResult result) { final targetData = result.notification.additionalData; if (targetData?['target_screen'] != null) { Navigator.pushNamed(context, '/target', arguments: targetData); } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: const Center(child: Text('Home Screen')), ); } }
5. 通知API请求参数调整
后端发送OneSignal通知时,需在additional_data中携带目标页面信息,示例请求:
{ "app_id": "YOUR_APP_ID", "include_player_ids": ["USER_PLAYER_ID"], "contents": {"en": "New message notification"}, "additional_data": { "target_screen": "target", "target_id": "123", "target_title": "Message from John" } }
关键注意点
- 冷态启动时必须在
runApp()前完成OneSignal通知数据获取,否则初始路由已设置为闪屏页无法拦截 - 跳转目标页时要确保返回栈中存在首页,避免返回直接退出应用
- 全局标记使用后及时重置,防止下次冷启动误触发
内容的提问来源于stack exchange,提问作者Mark Spector
相关产品推荐
相关产品推荐

