我在实时通知中追逐“Ghost” Bug的那一天

发布: (2026年3月23日 GMT+8 14:20)
4 分钟阅读
原文: Dev.to

Source: Dev.to

那个根本不存在的…还是存在?

几个月前,我在开发一款带实时通知的移动应用。功能看起来很直白:每当电商应用中有新订单产生时,用户应立即收到推送通知。

在开发阶段一切都运行得很完美——我的设备上通知几毫秒内就弹出了。但当 beta 测试者开始使用该应用时,出现了奇怪的现象:有些用户收到了重复的通知。感觉像在追逐幽灵。系统怎么会表现得如此不一致?

该应用使用 Firebase Cloud Messaging (FCM) 进行推送通知。我的最初怀疑对象是后端、移动框架,甚至是用户的设备。我一步步排查:

  • 检查后端日志——所有通知都已正确发送。
  • 认为问题是平台特定且微妙的。

经过数小时的调试,我发现罪魁祸首是:不小心注册了多个 Firebase 监听器

根本原因

在我的 Flutter 代码中大致是这样:

// Example listener registration (simplified)
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  // Handle incoming notification
  showNotification(message);
});

这个监听器在 每次用户导航到首页时都会被注册。每次导航都会新增一个监听器,所以如果用户来回切换三次,同一条通知就会被触发三次。此外,竞争条件有时会导致监听器在应用完全初始化之前就触发,从而出现延迟或丢失通知的情况。

解决方案

  1. 在应用启动时仅注册一次监听器(例如在 main() 或顶层 provider 中),并将其放在单一、集中的位置。
  2. showNotification() 具备幂等性,即使同一条消息到达多次,应用也只显示一次。
// Register once, e.g., in main()
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  FirebaseMessaging.onMessage.listen(_handleMessage);
  runApp(MyApp());
}

// Centralized handler
void _handleMessage(RemoteMessage message) {
  showNotification(message);
}

// Idempotent notification display
final Set _displayedMessageIds = {};

void showNotification(RemoteMessage message) {
  final String id = message.messageId ?? '';
  if (id.isEmpty || _displayedMessageIds.contains(id)) return;

  _displayedMessageIds.add(id);
  // TODO: Show the notification using your preferred method
}

收获

  • 幽灵 bug 往往源于细微的生命周期问题。
  • 在实时系统中,始终要考虑有多少监听器存在、它们何时触发,以及用户在应用中切换页面时会发生什么。
  • 将异步事件处理集中化可以防止重复操作,并让调试变得更加轻松。

对使用通知、异步事件或实时系统的开发者来说:务必仔细思考监听器的注册方式和生命周期管理——这可以为你省下数小时追逐幽灵的时间。

0 浏览
Back to Blog

相关文章

阅读更多 »