13. Doze模式与FCM:高优先级消息如何穿透

各位同学,今天我们来聊一个非常实际的问题——Doze模式下,FCM消息到底怎么穿透的?

说实话,这个问题我当年踩过不少坑。记得有一次,我们团队开发一款即时通讯App,测试阶段一切正常,结果一上线,用户反馈说「收不到消息了」。排查了半天,才发现是Doze模式在作祟。嗯,从那以后,我就把FCM的优先级机制研究了个底朝天。

13.1 先搞清楚:Doze模式对网络做了什么

Doze模式说白了就是系统帮你省电。它会把App的网络访问、同步、甚至闹钟都限制住。但问题是——省电和省事往往是矛盾的

你想想看,如果用户正在等一条重要的验证码,或者一条紧急的工作消息,结果因为Doze模式延迟了半小时才收到,这体验得多糟糕?

所以Google设计了一套「优先级穿透」机制。FCM消息可以携带一个priority字段,告诉系统:「这条消息很重要,别拦着。」

13.2 FCM的两种优先级:NORMAL vs HIGH

FCM消息的优先级分为两种:

优先级 含义 Doze模式下的行为
NORMAL 普通消息,可延迟 会被Doze模式限制,等到维护窗口才送达
HIGH 高优先级,立即送达 可以穿透Doze模式,系统会临时唤醒网络

我个人习惯是:能不用HIGH就不用。因为高优先级消息会打断Doze模式,频繁使用反而更耗电。但有些场景,比如支付通知、紧急告警,该用还得用。

13.3 高优先级消息的穿透流程

来,我们画张图,看看一条HIGH优先级消息是怎么「杀出重围」的。

FCM高优先级消息穿透Doze模式流程图 FCM 服务器 priority=HIGH 系统接收消息 检查优先级 HIGH? 临时唤醒网络 突破Doze限制 送达App 立即处理 延迟到维护窗口 等待Doze结束 延迟送达 可能数小时后

看到没?关键就在那个判断节点。系统收到FCM消息后,会先检查priority字段。如果是HIGH,系统会临时唤醒网络,让消息直达App。如果是NORMAL,那就乖乖排队,等Doze的维护窗口到了再说。

13.4 代码层面怎么配?

好,理论讲完了,咱们上代码。发送FCM消息时,优先级是这样设置的:

// 服务端发送FCM消息(使用Firebase Admin SDK)
const message = {
  token: '用户设备的FCM Token',
  notification: {
    title: '紧急通知',
    body: '您的订单已发货'
  },
  android: {
    priority: 'high',  // 关键:设置为高优先级
    ttl: 3600 * 1000   // 消息存活时间,单位毫秒
  }
};

admin.messaging().send(message)
  .then(response => {
    console.log('消息发送成功:', response);
  })
  .catch(error => {
    console.log('消息发送失败:', error);
  });

客户端这边,其实不需要额外配置。只要服务端发了priority: 'high',系统会自动处理。但有一点要注意——客户端必须在AndroidManifest中声明必要的权限

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

重要提醒:高优先级消息不等于「立即唤醒屏幕」。它只是让网络临时可用,App可以收到消息并处理。如果你想弹出通知或震动,还需要在onMessageReceived()中自行处理。

13.5 避坑指南:我曾经踩过的三个坑

讲到这里,我得分享几个实战中遇到的坑。嗯,都是真金白银换来的教训。

  1. 坑一:误以为HIGH优先级一定能穿透所有Doze

    我曾经以为只要设了priority: 'high',消息就一定能秒达。结果发现,在深度Doze模式下,系统还是会做一定限制。比如,如果设备长时间静止不动,系统会进入「空闲状态」,此时高优先级消息虽然能唤醒网络,但可能会有几百毫秒的延迟。所以,别指望毫秒级送达

  2. 坑二:滥用HIGH优先级导致耗电飙升

    有一次,我们团队把所有的FCM消息都设成了HIGH优先级。结果用户反馈手机耗电变快了。一查日志,发现设备频繁被唤醒,Doze模式几乎没生效。后来我们改成了:只有真正紧急的消息才用HIGH,其余都用NORMAL。耗电问题立刻缓解。

  3. 坑三:忽略TTL(Time To Live)设置

    TTL是消息的存活时间。如果不设置,默认是28天。这意味着,如果用户离线了,这条消息会在FCM服务器上存28天,等用户上线后再推送。但有些场景,比如验证码,过了5分钟就没意义了。所以,一定要根据业务场景设置合理的TTL。我一般把验证码类的TTL设为5分钟,普通通知设为1小时。

个人建议:如果你不确定某条消息该不该用HIGH优先级,可以问自己一个问题:「如果这条消息延迟半小时送达,用户会骂人吗?」如果会,就用HIGH;如果不会,就用NORMAL。简单粗暴,但很有效。

13.6 总结一下

好了,今天的内容就到这里。咱们回顾一下核心要点:

  • FCM的两种优先级:NORMAL(延迟送达)和HIGH(穿透Doze)
  • 穿透原理:系统收到HIGH消息后,临时唤醒网络,让消息直达App
  • 代码配置:服务端设置priority: 'high',客户端声明权限
  • 避坑指南:别滥用HIGH、别忽略TTL、别指望毫秒级送达

说实话,FCM的优先级机制设计得挺巧妙的。它既保证了紧急消息的及时性,又不会过度消耗电量。你想想看,如果没有这个机制,Doze模式就会变成一个「一刀切」的省电工具,用户体验反而会变差。

嗯,下一章我们聊聊更深入的话题——如何监控和调试Doze模式下的消息送达情况。到时候我会分享一些我常用的调试工具和技巧。


公众号:蓝海资料掘金营,微信deep3321