flutter_local_notification安卓端点击通知跳转context为空问题求助
问题原因及解决方法
核心原因
Android端出现NavigationService.navigatorKey.currentContext为空的情况,主要是以下两点:
- 冷启动场景下导航栈未初始化:当App被完全杀死后点击通知,Android会直接启动App并触发通知回调,此时MaterialApp还未完成build,全局导航键还未关联到有效的上下文。
- 回调触发时机过早:flutter_local_notification在Android上的通知点击回调,可能在App的Widget树完全构建完成前执行,导致
currentContext尚未被赋值。
解决方法
方法1:延迟执行导航跳转,确保上下文就绪
在回调中通过WidgetsBinding的addPostFrameCallback延迟执行导航操作,等待Widget树构建完成:
static _selectNotification(String payload, StreamChatClient client, RemoteMessage message) { debugPrint('notification payload: $payload'); // 等待Widget树完成构建,确保导航状态可用 WidgetsBinding.instance.addPostFrameCallback((_) { if (payload.contains('livestream')) { Utils.db.getLiveRoom(payload.split(":")[1]).then((liveRoom) { NavigationService.navigatorKey.currentState?.push( MaterialPageRoute<void>(builder: (context) => LiveRoomChat(liveRoom: liveRoom)), ); }); } else { List<String> ids = message.data['channel_id'].toString().split('_'); String receiverId = ''; if (ids[0] == Utils.user?.uid) { receiverId = ids[1]; } else { receiverId = ids[0]; } NavigationService.navigatorKey.currentState?.push( MaterialPageRoute<void>(builder: (context) => MessageApi( sourceType: Utils.friends.containsKey(receiverId) ? SourceType.friends : SourceType.justMet, receiverId: receiverId, channelId: payload.split(":")[1], streamToken: Utils.user?.streamToken ?? '', client: client )), ); } }); }
这里改用currentState?.push替代直接使用currentContext,currentState在导航栈初始化后会存在,可选链调用能避免空指针异常。
方法2:处理冷启动场景,缓存通知数据
如果App是从杀死状态被通知唤醒,需要先缓存payload和消息数据,等App首页初始化完成后再执行跳转:
- 全局定义变量缓存数据:
String? pendingNotificationPayload; RemoteMessage? pendingNotificationMessage; StreamChatClient? pendingClient;
- 修改
onSelectNotification,判断导航状态是否就绪:
static _selectNotification(String payload, StreamChatClient client, RemoteMessage message) { debugPrint('notification payload: $payload'); if (NavigationService.navigatorKey.currentState == null) { // 冷启动,缓存数据 pendingNotificationPayload = payload; pendingNotificationMessage = message; pendingClient = client; return; } // 后台唤醒,直接执行导航 _handleNavigation(payload, client, message); } // 抽离导航逻辑为独立方法 static void _handleNavigation(String payload, StreamChatClient client, RemoteMessage message) { if (payload.contains('livestream')) { Utils.db.getLiveRoom(payload.split(":")[1]).then((liveRoom) { NavigationService.navigatorKey.currentState?.push( MaterialPageRoute<void>(builder: (context) => LiveRoomChat(liveRoom: liveRoom)), ); }); } else { List<String> ids = message.data['channel_id'].toString().split('_'); String receiverId = ''; if (ids[0] == Utils.user?.uid) { receiverId = ids[1]; } else { receiverId = ids[0]; } NavigationService.navigatorKey.currentState?.push( MaterialPageRoute<void>(builder: (context) => MessageApi( sourceType: Utils.friends.containsKey(receiverId) ? SourceType.friends : SourceType.justMet, receiverId: receiverId, channelId: payload.split(":")[1], streamToken: Utils.user?.streamToken ?? '', client: client )), ); } }
- 在App首页的
initState中检查缓存并执行跳转:
class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (pendingNotificationPayload != null && pendingNotificationMessage != null && pendingClient != null) { _selectNotification._handleNavigation( pendingNotificationPayload!, pendingClient!, pendingNotificationMessage! ); // 清空缓存 pendingNotificationPayload = null; pendingNotificationMessage = null; pendingClient = null; } }); } // ... 其他页面代码 }
方法3:确认导航键的正确绑定
检查main.dart中导航键是否正确赋值给MaterialApp:
void main() { WidgetsFlutterBinding.ensureInitialized(); // 初始化其他依赖服务 runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( navigatorKey: NavigationService.navigatorKey, // 必须正确绑定此处 home: const HomePage(), // ... 其他配置项 ); } }
内容的提问来源于stack exchange,提问作者youcantgetridofmestackoverflow
相关产品推荐
相关产品推荐

