You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中App被杀死后点击Firebase通知不弹出对话框求助

问题原因分析

当App被完全杀死后点击通知启动属于冷启动场景,此时FirebaseMessaging.onMessageOpenedApp的监听器还未完成注册,无法捕获到触发App启动的这条通知消息——该监听器仅对App处于后台(未被杀死)时点击通知的场景生效。

另外,冷启动时App的上下文(navigatorKey.currentContext)可能还未初始化完成,即使能获取到消息,直接调用showAlertDialog也会因为上下文不存在而失败。

解决思路与代码调整

1. 捕获冷启动时的通知消息

使用FirebaseMessaging.instance.getInitialMessage()方法获取冷启动时触发App的通知消息,该方法会返回启动App的RemoteMessage(如果是通过通知启动),否则返回null。

2. 确保上下文可用后再弹窗

冷启动时App页面还未渲染完成,需要等待上下文初始化完成后再执行弹窗逻辑,可通过WidgetsBinding.instance.addPostFrameCallback实现。

3. 提取公共处理逻辑(避免重复代码)

把通知消息的处理逻辑提取成公共函数,减少代码冗余。

调整后的完整代码示例:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // 处理冷启动场景的通知
  RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
  if (initialMessage != null) {
    // 等待页面渲染完成,确保上下文可用
    WidgetsBinding.instance.addPostFrameCallback((_) {
      handleNotification(initialMessage);
    });
  }

  // 前台接收通知
  FirebaseMessaging.onMessage.listen(handleNotification);

  // 后台未杀死时点击通知
  FirebaseMessaging.onMessageOpenedApp.listen(handleNotification);

  runApp(MyApp(navigatorKey: navigatorKey));
}

// 公共通知处理函数
void handleNotification(RemoteMessage message) {
  RemoteNotification? notification = message.notification;
  if (notification == null) return;

  // 确保上下文已初始化
  if (navigatorKey.currentContext == null) return;

  if (notification.title == "Trip has ended") {
    try {
      showAlertDialog(
        navigatorKey.currentContext!,
        notification.title,
        notification.body,
        null,
      );
    } catch (e) {
      print(e);
    }
  } else if (notification.title == "Your driver is here" && notification.body != null) {
    String carImage = message.data['carImage'] ?? '';
    print("received $carImage");
    try {
      showAlertDialog(
        navigatorKey.currentContext!,
        notification.title,
        notification.body,
        carImage,
      );
    } catch (e) {
      print("error: $e");
    }
  }
}

// 你的MyApp实现
class MyApp extends StatelessWidget {
  final GlobalKey<NavigatorState> navigatorKey;

  const MyApp({super.key, required this.navigatorKey});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: navigatorKey,
      // 其他页面配置...
    );
  }
}

// 你的弹窗实现
void showAlertDialog(BuildContext context, String? title, String? body, String? carImage) {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: Text(title ?? ''),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (body != null) Text(body),
          if (carImage != null) Image.network(carImage),
        ],
      ),
      actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('确定'))],
    ),
  );
}

额外注意事项

  • 确保navigatorKey已正确绑定到MaterialApp的navigatorKey参数,否则currentContext会一直为null。
  • 测试冷启动场景时,需彻底杀死App(如在手机应用管理器中划掉App),而非仅后台运行。
  • 如果你的弹窗依赖特定页面状态,可考虑在首页的initState中处理getInitialMessage,确保页面已加载完成。

内容的提问来源于stack exchange,提问作者Majd Harb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 06:48:09