部分安卓设备(Oppo/Vivo/Redmi)无法接收Firebase FCM推送通知求助
解决Oppo/Vivo/Redmi及Nougat/Oreo设备FCM推送接收失败问题
我来帮你拆解下这个问题——这类FCM推送失效的情况,大多是国产ROM的后台限制和旧系统适配没做到位,咱们一步步来解决:
一、针对国产ROM(Oppo/Vivo/Redmi)的后台权限适配
这些品牌的定制ROM都有严格的后台进程管控,就算你配置了基础权限,App被后台杀死后还是无法接收推送,必须引导用户开启以下权限:
Redmi(小米):
- 开启「自启动管理」:设置 → 应用设置 → 应用管理 → 找到你的App → 自启动 → 允许自启动
- 关闭「省电策略」:设置 → 电池与性能 → 省电模式 → 选择「无限制」(针对你的App)
- 可通过代码引导用户跳转至设置页面:
Intent intent = new Intent(); intent.setAction("miui.intent.action.APP_PERM_EDITOR"); intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity"); intent.putExtra("extra_pkgname", getPackageName()); startActivity(intent);
Oppo:
- 开启「自启动权限」:设置 → 应用管理 → 应用列表 → 你的App → 自启动 → 允许
- 关闭「后台冻结」:设置 → 应用管理 → 应用列表 → 你的App → 耗电保护 → 关闭后台冻结
- 跳转设置页面代码:
Intent intent = new Intent(); intent.setAction("com.coloros.safecenter.startupapp.activity.StartupAppListActivity"); intent.setPackage("com.coloros.safecenter"); startActivity(intent);
Vivo:
- 开启「自启动权限」:设置 → 更多设置 → 权限管理 → 自启动 → 你的App → 允许
- 开启「高耗电权限」:设置 → 电池 → 后台高耗电 → 你的App → 允许
- 跳转设置页面代码:
Intent intent = new Intent(); intent.setAction("com.vivo.permissionmanager.activity.BgStartUpManagerActivity"); intent.setPackage("com.vivo.permissionmanager"); startActivity(intent);
二、Nougat(7.x)和Oreo(8.x)系统适配
1. Oreo(8.0+)必须创建通知渠道
从Android 8.0开始,没有通知渠道的推送会被系统直接拦截,务必在App启动时创建高优先级渠道:
private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( "your_unique_channel_id", "推送通知渠道", NotificationManager.IMPORTANCE_HIGH // 高优先级才能在后台弹出 ); channel.setDescription("接收App推送通知的渠道"); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } }
发送推送时,必须指定对应的channel_id参数。
2. Nougat(7.x)的Doze模式适配
Android 7.0引入的Doze模式会在设备闲置时限制后台进程,你需要:
- 在
AndroidManifest.xml中添加权限:<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> - 动态申请忽略电池优化权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); if (!pm.isIgnoringBatteryOptimizations(getPackageName())) { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } }
三、FCM消息类型选择与优先级设置
1. 优先使用Data Message而非Notification Message
- Notification Message:App后台时由系统托盘处理,但App被完全杀死后,部分国产ROM会拦截这类消息。
- Data Message:由你的
FirebaseMessagingService自行处理,需手动构建并显示通知,这种方式更稳定,不受系统托盘拦截影响。
示例Data Message结构(发送端):
{ "to": "device_token", "data": { "title": "新消息提醒", "body": "你有一条未读消息", "click_action": "OPEN_MAIN_ACTIVITY" }, "priority": "high" }
2. 强制设置消息优先级为High
针对Nougat及以下系统,务必将消息优先级设为high,这样才能唤醒后台进程:
- 发送的FCM payload中添加
"priority": "high" - 使用Firebase控制台发送时,选择「高优先级」选项
四、其他关键排查点
- 验证Token有效性:确保设备生成的Token已正确上传到服务器,且推送时使用的是最新Token。
- SHA指纹配置:在Firebase控制台项目设置中,务必添加App的SHA-1和SHA-256指纹(国产ROM对签名验证更严格)。
- Boot Receiver检查:确保
BootCompletedReceiver已正确注册,避免设备重启后无法重新注册FCM:<receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.QUICKBOOT_POWERON" /> </intent-filter> </receiver> - Wake Lock使用规范:获取Wake Lock后务必在操作完成后释放,避免耗电,同时使用
PARTIAL_WAKE_LOCK类型:PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YourApp::PushWakeLock"); wakeLock.acquire(10*60*1000L /*10分钟超时*/); // 处理推送逻辑后释放 wakeLock.release();
内容的提问来源于stack exchange,提问作者Khushboo Agarwal




