
android 11 下使用 php 发送 fcm 推送时,通知仅在屏幕点亮后才到达,根源在于混用 notification 消息与 data 消息——应改用纯 data 消息并由客户端完整处理通知展示逻辑,规避系统对后台 notification 消息的省电限制。
android 11 下使用 php 发送 fcm 推送时,通知仅在屏幕点亮后才到达,根源在于混用 notification 消息与 data 消息——应改用纯 data 消息并由客户端完整处理通知展示逻辑,规避系统对后台 notification 消息的省电限制。
在 Android 11 及更高版本中,Google 对后台执行和消息处理施加了更严格的电池优化策略。当您使用 notification 字段(即「Notification Message」)发送推送时,FCM 会将该消息交由系统通知管理器直接处理——但系统仅在设备处于活跃状态(如亮屏、前台应用运行或白名单豁免)时才允许显示通知;一旦设备进入深度休眠(如锁屏超时、Doze 模式),此类消息会被延迟甚至丢弃,直到用户唤醒设备。
而真正的解决方案是:改用 Data Only Message(纯数据消息)。这类消息始终通过 onMessageReceived() 回调传递给您的应用(即使应用在后台或进程被杀),由您完全控制通知的构建、触发与唤醒逻辑,从而绕过系统对 Notification 消息的限制。
✅ 正确的 PHP 发送代码(Data Only Message)如下:
<?php function sendPushNotification($to, $data = array()) {
// 关键:移除 'notification' 字段,仅保留 'data'
$fields = [
'to' => '/topics/' . $to,
'data' => $data, // ← 全部业务内容放在这里(title/body 等需自行解析)
// 可选:添加 'priority' 和 'time_to_live' 提升可靠性
'priority' => 'high',
'time_to_live' => 3600 // 1小时有效期
];
$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' => '您的配送单 #A12345 已开始派送',
'click_action' => 'FLUTTER_NOTIFICATION_CLICK', // 如为 Flutter 项目;原生 Android 可忽略或设为自定义 action
'sound' => 'default',
'badge' => '1'
];
sendPushNotification("myTopic", $data);
?>
⚠️ 注意事项与关键实践:
- 客户端必须处理所有通知逻辑:Android 端 onMessageReceived() 中需手动解析 remoteMessage.data,构建 NotificationCompat.Builder 并调用 notify() —— 不再依赖 remoteMessage.notification(它在 Data 消息中为 null)。
- 确保高优先级 + 唤醒能力:PHP 请求中务必设置 'priority' => 'high',并在 Android 客户端 onMessageReceived() 内正确申请 WakeLock(您当前的 wakeUpScreen() 实现基本合理,但建议使用 FLAG_KEEP_SCREEN_ON 或 PowerManager.FULL_WAKE_LOCK 配合 WakeLock.acquire(),并注意及时释放)。
- 检查应用是否被系统限制:在 Android 设置 → 电池 → 应用启动管理 / 自启动管理中,确认您的 App 已启用“允许后台活动”、“允许自启动”、“不受电池优化限制”。
- 避免混合消息类型:切勿同时包含 notification 和 data 字段(除非明确需要双路径分发),否则 FCM 会降级为 Notification Message 行为,导致锁屏失效。
? 总结:FCM 在 Android 11+ 的行为本质是「系统级管控」而非后端 Bug。PHP 侧无需复杂改造,只需切换至 Data Only Message 模式,并配合客户端完善后台唤醒与通知渲染逻辑,即可实现锁屏状态下秒级送达。这是 Google 官方推荐且经过验证的合规方案。











