关于手机进入深度睡眠时无法接收FCM通知的技术问询
解决FCM深度睡眠下无法即时接收Data通知的问题
首先得明确:虽然FCM的高优先级Data消息官方宣称可以唤醒设备,但国内安卓厂商的定制省电策略是这个问题的核心元凶,咱们从几个维度来排查和解决:
检查厂商系统的电池优化设置
几乎所有国内品牌(小米、华为、OPPO、vivo等)都有严格的后台省电机制,深度睡眠时会切断非白名单应用的网络和唤醒权限。你需要引导用户:- 进入系统设置 → 电池 → 电池优化
- 找到你的应用,设置为不允许优化
- 同时确保应用的“后台活动权限”“自启动权限”已经开启(不同厂商路径略有不同)
确认FCM消息的推送参数是否正确
你提到设置了"priority":"high",但要注意:- 对于Data类型消息,这个参数必须在服务器端的推送请求中设置,而不是客户端代码里
- 另外,Android 8.0+ 还需要配合
"content_available": true参数,确保系统会唤醒应用处理消息
正确的推送 payload 示例:
{ "to": "DEVICE_TOKEN", "priority": "high", "content_available": true, "data": { "title": "紧急通知", "body": "这是一条高优先级Data消息", "key1": "value1" } }优化FCM回调服务的代码逻辑
你的FCMCallbackService应该继承自FirebaseMessagingService,重写onMessageReceived方法时,建议添加临时唤醒锁来确保消息处理完成:public class FCMCallbackService extends FirebaseMessagingService { private static final String TAG = "FCMCallbackService"; private PowerManager.WakeLock wakeLock; @Override public void onMessageReceived(RemoteMessage remoteMessage) { // 获取唤醒锁,确保设备在处理消息时保持清醒 PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG + ":WakeLock"); wakeLock.acquire(3000); // 锁定3秒,足够处理消息和弹出通知 try { // 处理Data消息,构建并显示通知 if (remoteMessage.getData().size() > 0) { String title = remoteMessage.getData().get("title"); String body = remoteMessage.getData().get("body"); showNotification(title, body); } } finally { // 释放唤醒锁 if (wakeLock != null && wakeLock.isHeld()) { wakeLock.release(); } } } private void showNotification(String title, String body) { // 构建通知的逻辑,注意Android 8.0+需要创建通知渠道 NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("high_priority_channel", "高优先级通知", NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "high_priority_channel") .setSmallIcon(R.drawable.ic_notification) .setContentTitle(title) .setContentText(body) .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true); notificationManager.notify(1, builder.build()); } }这里的唤醒锁是临时的,不会长期占用设备资源,只是确保消息处理和通知展示的过程中设备不会立刻回到睡眠。
额外注意事项
- 避免使用已废弃的
FirebaseInstanceIdService,确保使用最新的FirebaseMessagingService - 测试时一定要用真实设备的深度睡眠状态,不要用模拟器,模拟器的睡眠机制和真实设备差异很大
- 某些厂商的“极致省电模式”会完全切断所有后台应用,这种情况下即使设置了白名单也可能无效,需要引导用户关闭该模式或者把应用加入例外
- 避免使用已废弃的
内容的提问来源于stack exchange,提问作者Daveron
相关产品推荐
相关产品推荐

