
android 11 设备在锁屏状态下无法及时接收 php 后端发送的 fcm 推送,根本原因在于使用了「通知消息(notification message)」而非「数据消息(data message)」,导致系统受后台执行限制与省电策略影响而延迟投递。
android 11 设备在锁屏状态下无法及时接收 php 后端发送的 fcm 推送,根本原因在于使用了「通知消息(notification message)」而非「数据消息(data message)」,导致系统受后台执行限制与省电策略影响而延迟投递。
FCM 消息分为两类:通知消息(Notification Message) 和 数据消息(Data Message)。前者由 Firebase 自动处理——即使应用进程被杀或设备锁屏,系统级通知栏仍可显示,但 Android 8.0+(尤其是 Android 11)对后台服务和唤醒行为施加了严格限制,当仅发送 notification 字段时,FCM 可能将消息降级为“高优先级但非强制唤醒”,实际投递严重依赖系统调度,导致锁屏后延迟甚至丢弃。
而 数据消息(Data Message) 则不同:它始终通过 onMessageReceived() 回调送达应用层(即使应用在后台或进程被杀),由开发者完全控制通知构建与唤醒逻辑,从而绕过系统对通知消息的节流机制。因此,修复的关键是:PHP 后端必须发送纯 data 字段的消息,移除 notification 字段,并确保 Android 端正确响应 RemoteMessage.getData()。
✅ 正确的 PHP 发送代码(数据消息示例):
<?php
function sendPushNotification($to, $data = array()) {
// 关键:仅保留 data 字段,移除 notification 字段
$fields = [
'to' => '/topics/' . $to,
'data' => $data, // ← 核心:使用 data 而非 notification
'priority' => 'high', // 必须设为 high 才可能唤醒设备
'time_to_live' => 3600 // 可选:设置存活时间(秒)
];
$headers = [
'Authorization: key=MY_SECRET_FCM_KEY',
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result, true);
}
// 示例调用:发送纯数据消息
$data = [
'title' => '订单已更新',
'body' => '您的配送单状态已变更',
'click_action' => 'FLUTTER_NOTIFICATION_CLICK' // Android 专用:点击跳转标识(如需)
];
sendPushNotification("myTopic", $data);
?>⚠️ 注意事项:
不要混用 notification 和 data 字段:若同时存在,FCM 会以「通知消息」模式投递,onMessageReceived() 在后台/锁屏时不会被调用(仅前台生效),导致你的 wakeUpScreen() 逻辑失效。
-
Android 端必须监听 data 字段:在 onMessageReceived() 中改用 remoteMessage.getData() 解析内容,而非 remoteMessage.getNotification():
override fun onMessageReceived(remoteMessage: RemoteMessage) { Log.d(TAG, "Data message received: ${remoteMessage.data}") // ✅ 从 data 中提取内容 val title = remoteMessage.data["title"] ?: "默认标题" val body = remoteMessage.data["body"] ?: "默认内容" // 构建并显示通知(含唤醒逻辑) wakeUpScreen() showNotification(title, body) } 确保 priority: "high" + time_to_live:这是触发系统唤醒的关键参数;低优先级消息会被延迟或丢弃。
验证 Android 权限与配置:确认 AndroidManifest.xml 中已声明 WAKE_LOCK 和 POST_NOTIFICATIONS(Android 12+)权限,并在运行时动态申请(如适用)。
? 总结:PHP 后端问题本质并非代码缺陷,而是消息类型误用。将 notification 替换为 data、设置 priority: high、并在 Android 端统一从 data 解析内容,即可稳定实现锁屏唤醒与即时推送。此方案兼容 Android 11+ 后台限制,且无需关闭电池优化(用户侧更友好)。


















