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

Android Kotlin项目:应用关闭时如何显示悬浮通知?

解决Android应用关闭后Service无法推送悬浮通知的问题

核心原因

应用关闭后系统会限制或杀死后台Service,导致你的io.socket连接中断,自然收不到推送通知。以下是针对性的解决方案:


1. 将Service改为前台Service(API 26+强制要求)

Android 8.0及以上版本,后台Service会被系统主动回收,必须使用前台Service才能在后台持续运行,同时需要展示一个常驻通知(可设置为低干扰模式)。

实现步骤:

  • 先创建前台服务的通知渠道(API 26+必须):
private fun createServiceNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            "SOCKET_SERVICE_CHANNEL",
            "Socket连接服务",
            NotificationManager.IMPORTANCE_LOW // 低优先级,避免打扰用户
        ).apply {
            description = "维持Socket连接的后台服务"
        }
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }
}
  • 在Service的onStartCommand中启动前台:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    createServiceNotificationChannel()
    
    val notification = NotificationCompat.Builder(this, "SOCKET_SERVICE_CHANNEL")
        .setContentTitle("后台服务运行中")
        .setContentText("维持Socket连接")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_LOW)
        .build()

    // 启动前台服务
    startForeground(1, notification)

    // 初始化/重建io.socket连接
    initSocketConnection()

    return START_STICKY // 进程被杀后,系统内存充足时会重启Service
}

2. 确保悬浮通知的渠道优先级足够高

悬浮通知(Heads-up)需要通知渠道优先级设为高/紧急,否则应用后台时可能无法弹出:

// 创建推送通知专属渠道(和前台服务渠道分开)
private fun createPushNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            "PUSH_NOTIFICATION_CHANNEL",
            "悬浮推送通知",
            NotificationManager.IMPORTANCE_HIGH // 必须设为高优先级
        ).apply {
            description = "接收Socket推送的悬浮通知"
            enableVibration(true)
            setShowBadge(true)
        }
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }
}

// 发送悬浮通知的逻辑
fun showHeadsUpNotification(title: String, content: String) {
    val notification = NotificationCompat.Builder(this, "PUSH_NOTIFICATION_CHANNEL")
        .setContentTitle(title)
        .setContentText(content)
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setCategory(NotificationCompat.CATEGORY_ALARM) // 提升悬浮显示概率
        .build()

    val notificationManager = NotificationManagerCompat.from(this)
    notificationManager.notify(System.currentTimeMillis().toInt(), notification)
}

3. 处理进程被杀后的Socket重连

系统重启Service后,需要重新建立io.socket连接,把连接逻辑放在onStartCommand或onCreate中,确保每次Service启动都能重连:

private fun initSocketConnection() {
    // 先断开旧连接(如果存在)
    socket?.disconnect()
    
    // 初始化新连接
    socket = IO.socket("你的Socket服务器地址")
    socket?.on(Socket.EVENT_CONNECT) {
        // 连接成功回调
    }
    socket?.on("push_notification") { args ->
        // 收到推送后展示悬浮通知
        val title = args[0] as String
        val content = args[1] as String
        showHeadsUpNotification(title, content)
    }
    socket?.connect()
}

4. 规避厂商后台管控

国内大部分厂商(小米、华为、OPPO等)有独立的后台管控机制,即使是前台Service也可能被杀死,需要引导用户:

  • 将应用加入后台白名单
  • 关闭电池优化
  • 允许自启动

也可以在代码中主动请求忽略电池优化权限:

private fun requestIgnoreBatteryOptimizations() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
        intent.data = Uri.parse("package:$packageName")
        startActivity(intent)
    }
}

5. 适配Android 12+后台启动限制

Android 12(API 31)及以上版本,后台启动Service的限制更严格,若需应用完全关闭后仍能维持连接,可配合WorkManager或AlarmManager定期唤醒并重建连接(WorkManager适合周期性任务,AlarmManager可实现精确唤醒,但会增加功耗)。


内容的提问来源于stack exchange,提问作者chanthini begam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:30:10