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

安卓锁屏/休眠时即时接收服务器消息的服务应用开发方案咨询

最佳实现方案与代码示例

首先明确:主流即时通讯APP(如Whatsapp、Telegram)的核心通知机制是系统级推送服务(FCM/APNs),而非WebSocket。以下是详细分析和实现代码:

一、方案对比:Push Notification vs WebSocket

Push Notification(系统推送)

  • 优势:系统原生支持,锁屏下直接由系统触发通知,无需APP保持后台进程;厂商对系统推送优先级极高,几乎不会被后台限制影响,兼容性覆盖所有设备。
  • 不足:极端情况下可能有秒级延迟,但主流服务商(FCM/APNs)的即时性已经能满足绝大多数场景需求。

WebSocket长连接

  • 优势:理论上双向通信即时性更高。
  • 不足:后台保活难度极大——Android的Doze模式、厂商后台查杀,iOS的后台进程限制,都会导致连接断开,无法保证锁屏下稳定运行,还会额外增加设备耗电量。

二、最佳实践

优先采用系统推送服务作为核心通知机制,仅在APP前台在线时用WebSocket做补充(比如实时聊天场景)。这种组合既能保证锁屏下的即时通知,又能兼顾前台的低延迟体验。


示例代码

一、Android端(FCM系统推送 + WebSocket前台补充)

1. FCM推送接收与锁屏通知展示

// MyFirebaseMessagingService.kt
class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        
        // 构建锁屏可见的通知
        val notificationBuilder = NotificationCompat.Builder(this, "IM_CHANNEL")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(remoteMessage.notification?.title ?: "新消息")
            .setContentText(remoteMessage.notification?.body ?: "您收到一条新消息")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // 强制锁屏下显示完整内容

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        // Android 8.0+ 必须创建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "IM_CHANNEL",
                "即时消息通知",
                NotificationManager.IMPORTANCE_HIGH
            )
            notificationManager.createNotificationChannel(channel)
        }
        notificationManager.notify(System.currentTimeMillis().toInt(), notificationBuilder.build())
    }
}

2. WebSocket前台连接示例(基于OkHttp)

// WebSocketManager.kt
class WebSocketManager(private val context: Context) {
    private var webSocket: WebSocket? = null

    fun connect() {
        val client = OkHttpClient()
        val request = Request.Builder().url("wss://your-server-domain/ws").build()
        webSocket = client.newWebSocket(request, object : WebSocketListener() {
            override fun onOpen(webSocket: WebSocket, response: Response) {
                // 连接成功后发送身份验证
                webSocket.send("auth:user_12345")
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                // 前台收到消息时弹出通知
                showForegroundNotification(text)
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                // 处理连接失败,可加入重连逻辑
            }
        })
    }

    private fun showForegroundNotification(message: String) {
        val notificationBuilder = NotificationCompat.Builder(context, "IM_CHANNEL")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle("实时消息")
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)

        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(System.currentTimeMillis().toInt()+1, notificationBuilder.build())
    }

    fun disconnect() {
        webSocket?.close(1000, "主动断开连接")
    }
}

二、iOS端(APNs系统推送 + WebSocket前台补充)

1. APNs推送接收与通知展示

// AppDelegate.swift
import UIKit
import UserNotifications

@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 请求通知权限
        UNUserNotificationCenter.current().delegate = self
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, _ in
            if granted {
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            }
        }
        return true
    }

    // 后台/锁屏下接收推送
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if let aps = userInfo["aps"] as? [String: Any],
           let alert = aps["alert"] as? [String: String] {
            let title = alert["title"] ?? "新消息"
            let body = alert["body"] ?? "您收到一条新消息"
            showNotification(title: title, body: body)
        }
        completionHandler(.newData)
    }

    // 前台接收推送时显示通知
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .sound, .badge])
    }

    private func showNotification(title: String, body: String) {
        let content = UNMutableNotificationContent()
        content.title = title
        content.body = body
        content.sound = .default
        content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber

        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
        UNUserNotificationCenter.current().add(request)
    }
}

2. WebSocket前台连接示例(基于Starscream)

// WebSocketManager.swift
import Starscream

class WebSocketManager: WebSocketDelegate {
    private var webSocket: WebSocket?

    func connect() {
        guard let url = URL(string: "wss://your-server-domain/ws") else { return }
        var request = URLRequest(url: url)
        request.timeoutInterval = 5
        webSocket = WebSocket(request: request)
        webSocket?.delegate = self
        webSocket?.connect()
    }

    func didReceive(event: WebSocketEvent, client: WebSocket) {
        switch event {
        case .connected(let headers):
            print("WebSocket连接成功: \(headers)")
            webSocket?.write(string: "auth:user_12345")
        case .text(let message):
            print("收到WebSocket消息: \(message)")
            showForegroundNotification(message: message)
        case .disconnected(let reason, let code):
            print("WebSocket断开: \(reason) 代码: \(code)")
        case .error(let error):
            print("WebSocket错误: \(error?.localizedDescription ?? "未知错误")")
        default: break
        }
    }

    private func showForegroundNotification(message: String) {
        let content = UNMutableNotificationContent()
        content.title = "实时消息"
        content.body = message
        content.sound = .default
        content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber

        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
        UNUserNotificationCenter.current().add(request)
    }

    func disconnect() {
        webSocket?.disconnect()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:31:41