You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

部分安卓设备(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

火山引擎 最新活动