Android 11下PHP发送FCM通知仅亮屏时送达问题排查
问题根因
你遇到的锁屏状态下推送延迟、亮屏才收到的问题,核心原因是后端发送FCM消息时未指定高优先级,消息默认使用normal普通优先级投递。
Android 6.0及以上版本引入的Doze省电机制,会在设备锁屏静置一段时间后限制后台网络活动、延迟批量处理非高优先级任务:普通优先级的FCM消息会被FCM服务端临时缓存,直到设备亮屏、充电退出Doze状态后才会批量投递到设备;只有标记为high优先级的消息,FCM会尝试即时唤醒设备建立连接投递,不受Doze模式限制。这也能解释为什么Firebase控制台发的测试推送能在锁屏时即时送达——控制台发送测试消息默认会标记为高优先级。
后端PHP代码修复
修改发送FCM请求的消息体,补充高优先级标记和Android端专属投递配置即可,修正后的代码如下:
<?php function sendPushNotification($to, $data = array()){ $fields = array( 'to' => '/topics/' . $to, 'notification' => $data, 'priority' => 'high', // 全局标记消息为高优先级,允许穿透Doze模式即时投递 'android' => array( 'priority' => 'high', // Android平台专属高优先级标记,适配新版FCM投递规则 'ttl' => '0s' // 消息不做离线缓存,避免设备上线后收到过期的旧推送,可根据业务需求调整时长 ) // 若需要绑定特定通知渠道,放开下方注释,值与Android端定义的channelId保持一致 // ,'android_channel_id' => '你的通知渠道ID' ); $headers = array( 'Authorization: key=MY_SECRET_FCM_KEY', 'Content-Type: application/json' ); $url = 'https://fcm.googleapis.com/fcm/send'; $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_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields)); $result = curl_exec($ch); curl_close($ch); // 原代码return后写的echo "ok"是永远不会执行的死代码,直接删除即可 return json_decode($result, true); } $data = array( 'title' => 'title', 'body' => 'body' ); sendPushNotification("myTopic", $data); ?>
注意事项
- 高优先级消息有配额限制,Google会根据应用的用户交互数据动态调整高优先级消息配额,滥发高优先级消息会被自动降为普通优先级,仅对需要即时触达的推送使用高优先级标记。
- 如果推送携带自定义业务参数、需要保证无论应用在前台/后台/被杀都能触发你自定义的
onMessageReceived逻辑,不要仅使用notification字段传参,需要将业务参数放到独立的data字段中传递,纯notification消息在部分定制ROM上会由系统直接托管弹出,不会走你自定义的服务逻辑。
Android端可选优化(提升投递稳定性)
你现有Android端代码有几个细节问题可以顺手调整,进一步降低推送延迟概率:
- 通知渠道创建逻辑不要放在
onMessageReceived里执行,应该在应用启动初始化阶段就完成通知渠道创建,避免第一次收到消息时才创建渠道导致通知弹出延迟。 - 代码中模拟发送
ACTION_POWER_CONNECTED系统广播的逻辑没有实际作用,Android 10及以上版本第三方应用发送这类系统专属广播会被系统直接拦截,甚至可能触发系统异常行为检测,直接删除即可。 - 现有亮屏逻辑使用的
SCREEN_DIM_WAKE_LOCK在API 17之后已经废弃,Android 11上兼容性不佳,建议替换为官方推荐的setFullScreenIntent方案实现锁屏状态下通知弹出亮屏,不需要手动申请过时的WakeLock。
内容的提问来源于stack exchange,提问作者Seng Phrakonkham
相关产品推荐
相关产品推荐

