恢复网络后FCM通知无法稳定送达的问题求助
我在Web应用中集成了FCM Web Push实现通知功能,目前处于测试阶段,已在多台Android和Windows设备的Chrome、Edge浏览器上验证。用户订阅推送时会注册Service Worker,设备在线且网络正常时能立即接收通知,但Android设备断网后恢复连接时,通知送达情况随机:有时全部收到,有时完全收不到,有时仅收到部分。发送通知后FCM返回所有Token成功,说明消息已送达FCM服务器,但设备端存在丢通知的情况。
前台接收通知代码
var firebaseConfig = { apiKey: "", authDomain: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "" }; firebase.initializeApp(firebaseConfig); fcmMessaging = firebase.messaging(); fcmMessaging.onMessage((payload) => { cuteToast({ type: 'success', message: payload.notification.body, timer: 5000 }); });
Service Worker代码(firebase-messaging-sw.js)
importScripts("https://www.gstatic.com/firebasejs/9.9.4/firebase-app-compat.js"); importScripts("https://www.gstatic.com/firebasejs/9.9.4/firebase-messaging-compat.js"); // Initialize the Firebase app in the service worker by passing in the // messagingSenderId. const app = firebase.initializeApp({ apiKey: "", authDomain: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "" }); const messaging = firebase.messaging();
注:未重写onBackgroundMessage(),使用默认推送通知逻辑处理。
PHP发送通知代码
$url = 'https://fcm.googleapis.com/fcm/send'; $fields = json_encode(array ( 'registration_ids' => $tokens, 'notification' => array ( 'title'=>$subject."-".date("H:i d.m.Y"), 'body'=>br2nl($message,""), 'icon'=>'./bug.png', 'click_action'=>$clickUrl ), 'data'=>array( 'click_action'=>$clickUrl ), 'priority'=>'high', 'time_to_live'=>86400, 'webpush'=>array( 'headers'=>array( 'TTL'=>86400, 'Urgency'=>'High' ) ), 'android'=>array( 'ttl'=>'86400s', 'priority'=>'high' ), 'apns'=>array( 'header'=>array( 'apns-priority'=>10, 'apns-expiration'=>time() + 86400 ) ) )); $headers = array ( 'Authorization: key=', 'Content-Type: application/json' ); $ch = curl_init (); curl_setopt ( $ch, CURLOPT_URL, $url ); curl_setopt ( $ch, CURLOPT_POST, true ); curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers ); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true ); curl_setopt ( $ch, CURLOPT_POSTFIELDS, $fields ); $result = json_decode(curl_exec ( $ch )); curl_close ( $ch );
问题原因及解决方法
1. Web Push消息存储与系统限制
虽然设置了time_to_live和TTL为86400秒,但Android上的Chrome/Edge在设备长时间离线或深度休眠时,系统可能限制Service Worker唤醒,甚至清理缓存的推送消息。另外FCM对批量发送的消息可能合并或丢弃部分低优先级内容(即使标记了high优先级)。
解决方法:
- 确保
priority: high和Web Push的Urgency: High配置同时生效,避免系统忽略消息。 - 关键通知拆分批量发送为单条发送,减少FCM合并消息的概率。
2. Service Worker激活状态异常
Android设备断网恢复后,Service Worker可能因长时间无活动被浏览器终止,无法接收推送消息。
解决方法:
- 显式定义
onBackgroundMessage()方法,确保Service Worker在后台消息到达时被唤醒:
messaging.onBackgroundMessage((payload) => { const notificationTitle = payload.notification.title; const notificationOptions = { body: payload.notification.body, icon: payload.notification.icon }; self.registration.showNotification(notificationTitle, notificationOptions); });
- 在Web应用前台添加定期心跳请求(比如每15分钟发送一个小请求),维持Service Worker活跃状态。
3. Android电池优化限制
Android的Doze模式、App Standby等电池优化功能会限制后台浏览器的网络访问与唤醒,导致消息无法送达或丢失。
解决方法:
- 引导用户将Chrome/Edge添加到电池优化白名单,允许后台运行。
- 改用
data消息发送关键通知:notification消息由FCM客户端直接展示,data消息需Service Worker处理,系统对其唤醒限制更宽松。修改发送代码,将通知内容移至data字段,在Service Worker中处理展示逻辑。
4. FCM Token有效性问题
即使FCM返回发送成功,设备断网期间Token可能因浏览器清缓存、用户重新登录等失效,FCM不会立即返回失败,而是后续清理无效Token。
解决方法:
- 添加Token刷新监听,及时更新后端存储的Token:
fcmMessaging.onTokenRefresh(() => { fcmMessaging.getToken().then((refreshedToken) => { // 将新Token发送到后端更新 }).catch((err) => { console.log('获取新Token失败', err); }); });
- 定期通过FCM API验证Token有效性,清理无效Token。
5. 消息合并导致丢失
FCM对同一设备的多条离线消息,可能按优先级合并,只保留最新的部分消息。
解决方法:
- 为每条消息设置唯一的
collapse_key,不同collapse_key的消息会被单独存储。如果需要保留所有消息,确保每条消息使用不同的collapse_key:
'collapse_key' => uniqid() // 添加到$fields数组中
内容的提问来源于stack exchange,提问作者Denis Fajertag

