如何为关键通知申请豁免 Doze 模式?
解读
面试官问“豁免 Doze”并不是想听“把应用加到电池白名单”这种一句话答案,而是考察候选人是否真正理解:
- Doze 的“打盹”与“空闲维护窗口”机制在国内 ROM 上的差异;
- 通知通道优先级、前台服务、FCM 高优先级消息、AlarmManager、后台启动限制之间的取舍;
- 国内无 GMS 环境下如何把“系统级高优先级消息”落到自研推送通道;
- 豁免之后仍被厂商省电策略二次限制时的兜底方案。
一句话:既要让系统认可“这条通知确实关键”,又要在国内复杂生态里跑得通。
知识点
- Doze 模式:API 23 引入,分 LIGHT-IDLE 与 DEEP-IDLE;国内 ROM(EMUI、MIUI、ColorOS 等)在 AOSP 基础上追加“对齐唤醒”“冰封”等二次省电。
- 通知优先级:NotificationManager.IMPORTANCE_HIGH 仅保证通道级别,不突破 Doze。
- 前台服务:startForeground() + 对应渠道 IMPORTANCE_HIGH,在 Doze 下仍可弹出通知,但 targetSdk≥34 需立即显示,否则 ANR。
- 高优先级 FCM:priority="high" + 服务器标记 urgent,Doze 下可临时唤醒应用 10 s;国内无 GMS 时由厂商推送接管(华为 Push Kit、小米 MiPush 等),需申请对应“高优消息”权限。
- 白名单:REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 跳转系统设置,用户手动确认;厂商白名单(如小米“自启动”、华为“手动管理”)需额外引导。
- AlarmManager:setExactAndAllowWhileIdle() 与 setAlarmClock() 可在 Doze 触发闹钟,但频次受限;通知类场景不推荐。
- 后台启动限制:targetSdk≥31 需持有 android.permission.START_ACTIVITIES_FROM_BACKGROUND 或使用全屏 Intent 通知。
- Tiramisu 通知权限:POST_NOTIFICATIONS 必须动态申请,否则通知直接被系统丢弃。
答案
分四步落地,兼顾 AOSP 与国内 ROM:
-
通道与通知属性
- 创建 NotificationChannel,setImportance(IMPORTANCE_HIGH);
- 通知构建时 setCategory(Notification.CATEGORY_ALARM) 或 CATEGORY_CALL,系统默认给予横幅与提示音;
- 若需亮屏,附加 FLAG_HIGH_PRIORITY 与 fullScreenIntent,同时申请 USE_FULL_SCREEN_INTENT 权限。
-
保证“前台服务”身份
- 在接收到推送或事件时立即启动前台服务(startForegroundService),并在 5 s 内调用 startForeground();
- 服务 ID 与通知 ID 保持一致,避免 ANR;
- 服务 onStartCommand 返回 START_STICKY,防止被系统回收。
-
申请白名单与厂商权限
- 运行时检测 PowerManager.isIgnoringBatteryOptimizations,若为 false,通过 Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) 引导用户;
- 在华为/小米/OPPO 等机型,同步申请“自启动”“后台弹出界面”“锁屏后保持运行”三大权限,提供一键跳转工具类;
- 将应用加入厂商“后台保护”名单,否则 Doze 豁免后仍可能被“冰封”。
-
无 GMS 场景下的高优消息
- 服务端按厂商要求申请“高优消息”配额(华为最高 3000 条/天,小米 1000 条/天);
- 客户端在自定义 BroadcastReceiver 中收到高优消息后,同样走“前台服务+高优先级通知”路径,确保弹窗;
- 记录事件埋点,监控因配额耗尽导致的降级,触发短信或电话兜底。
通过以上四步,即可在 Doze 模式与国内二次省电策略下,把“关键通知”送达率从 30% 提升到 95% 以上。
拓展思考
- 折叠屏/多窗口场景:应用处于分屏且设备进入 Doze,通知 fullScreenIntent 只会显示在焦点窗口,需额外判断 Activity 生命周期,避免重复弹窗。
- 隐私沙盒与 T+ 版本:Android 14 收紧后台启动限制,前台服务必须关联用户可见任务,可考虑改用 UserInitiatedDataTransferJob(UIDTJob)替代传统 FGS。
- 省电统计与负反馈:豁免白名单后,若应用 wakeup 次数过高,会被系统记录到 App Standby Bucket 的“频繁使用”组,反而增加被限制概率;需内部收敛无用唤醒,保持每日 wakeup < 10 次。
- 云端动态降级:高优消息配额耗尽时,服务端可实时切换为“普通优先级+短信补推”的混合通道,客户端通过 Firebase Remote Config 或自研配置中心实时拉取策略,实现无人值守的弹性降级。