You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

收到FCM推送时唤醒Android屏幕及相关功能实现与问题排查

问题解答

一、推送唤醒屏幕(后台/杀死状态生效)

现有代码的问题

你的wakeApp()方法在屏幕熄灭数分钟后失效,核心原因有两个:

  • FCM消息类型限制:如果推送是带notification字段的通知消息,APP后台或被杀死时,系统会直接展示通知,不会触发onMessageReceived();只有纯data字段的数据消息,才能在任何状态下触发该方法。
  • WakeLock使用不当:FULL_WAKE_LOCK已在API 17废弃,且你acquire()后立刻release(),系统可能还没完成唤醒操作就释放了锁,导致唤醒失败;同时Android 12+对WakeLock的权限和参数有更严格限制。

正确实现方案

  1. 强制使用FCM数据消息
    发送推送时仅包含data字段,示例Payload:

    {
      "data": {
        "title": "新通知",
        "body": "测试唤醒消息",
        "need_wake": "true"
      },
      "to": "设备令牌"
    }
    

    这样无论APP处于前台、后台还是被杀死,都会触发onMessageReceived()。

  2. 修改唤醒逻辑

    • 先在AndroidManifest.xml添加必要权限:
      <uses-permission android:name="android.permission.WAKE_LOCK" />
      <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <!-- 可选,用于解锁锁屏 -->
      
    • 替换唤醒代码:
      private fun wakeScreen() {
          val pm = applicationContext.getSystemService(POWER_SERVICE) as PowerManager
          if (!pm.isInteractive) {
              val wakeLockTag = "$packageName:WAKELOCK"
              // 根据系统版本选择合适的WakeLock参数
              val wakeLockFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                  PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP
              } else {
                  PowerManager.SCREEN_DIM_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.ON_AFTER_RELEASE
              }
              val wakeLock = pm.newWakeLock(wakeLockFlags, wakeLockTag)
              wakeLock.acquire(10000L) // 持有10秒,确保屏幕完成唤醒
      
              // 适配Android版本解锁锁屏
              val keyguardManager = applicationContext.getSystemService(KEYGUARD_SERVICE) as KeyguardManager
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                  // Android 8+ 需通过Activity请求解锁
                  val intent = Intent(this, TransparentWakeActivity::class.java)
                  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                  startActivity(intent)
              } else {
                  val keyguardLock = keyguardManager.newKeyguardLock(wakeLockTag)
                  keyguardLock.disableKeyguard()
              }
          }
      }
      
    • 注:Android 10+ 无法直接禁用锁屏,需创建一个透明Activity调用keyguardManager.requestDismissKeyguard()完成解锁。
  3. 适配国产ROM后台限制
    小米、华为、OPPO等品牌的ROM有严格的后台杀进程机制,需引导用户给APP开启「后台运行权限」「自启动权限」,否则APP被杀死后可能无法接收FCM消息。

二、静音模式下通知发声

要实现静音模式下通知仍发声,核心是创建绕过免打扰的高优先级通知渠道:

  1. 创建通知渠道(Android 8+)

    private fun createHighPriorityChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "urgent_notification_channel"
            val channel = NotificationChannel(channelId, "紧急通知", NotificationManager.IMPORTANCE_HIGH).apply {
                description = "静音模式下仍可发声的通知"
                // 设置铃声并指定音频属性
                setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), 
                    AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .build())
                enableVibration(true)
                // 关键:绕过免打扰(静音)模式
                setBypassDnd(true)
            }
            val notificationManager = getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(channel)
        }
    }
    
  2. 构建高优先级通知
    在onMessageReceived()中调用:

    private fun showUrgentNotification(title: String, body: String) {
        val intent = packageManager.getLaunchIntentForPackage(packageName)
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, 
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
        
        val notificationBuilder = NotificationCompat.Builder(this, "urgent_notification_channel")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(body)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            // 兼容Android 7及以下,设置最高优先级绕过静音
            .setPriority(NotificationCompat.PRIORITY_MAX)
        
        NotificationManagerCompat.from(this).notify(System.currentTimeMillis().toInt(), notificationBuilder.build())
    }
    

总结

  • 唤醒屏幕:必须用FCM数据消息触发onMessageReceived(),使用适配系统版本的WakeLock参数并持有足够时间,同时引导用户开启ROM后台权限。
  • 静音发声:创建带setBypassDnd(true)的高优先级通知渠道,构建通知时指定对应优先级。

内容的提问来源于stack exchange,提问作者Itamar Stern

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 06:00:12