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

Swift中App进入后台时如何保持WebSocket连接?

iOS后台维持URLSessionWebSocketTask连接的可行方案

1. 改用后台URLSession配置

你当前使用的.default会话配置在App进入后台后会被系统挂起,需要替换为后台专用配置,确保会话能在后台继续运行:

private var websocket: URLSessionWebSocketTask?
private var urlSession: URLSession? // 保留会话引用,避免被提前释放

func connectWebsocket() {
    // 创建带唯一标识符的后台会话配置,用于系统唤醒App时识别
    let config = URLSessionConfiguration.background(withIdentifier: "com.your.app.websocket.background")
    config.sessionSendsLaunchEvents = true // 可选:会话有事件时唤醒App
    config.isDiscretionary = false // 立即执行任务,不等待系统空闲
    
    urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
    
    guard let url = URL(string: "ws://URL...") else { return }
    websocket = urlSession?.webSocketTask(with: url)
    websocket?.resume()
}

2. 申请后台任务断言延长活跃时间

App进入后台后,系统会快速挂起进程,需要申请后台任务断言获得额外运行时间,用来发送心跳包维持连接:

private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

func sceneDidEnterBackground(_ scene: UIScene) {
    // 申请后台任务,超时后自动结束
    backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "WebSocketKeepAlive") { [weak self] in
        UIApplication.shared.endBackgroundTask(self?.backgroundTaskID ?? .invalid)
        self?.backgroundTaskID = .invalid
    }
    
    // 启动心跳定时器,建议30-60秒发送一次ping包
    startHeartbeatTimer()
}

private func startHeartbeatTimer() {
    Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] timer in
        guard let websocket = self?.websocket else {
            timer.invalidate()
            return
        }
        
        websocket.send(.ping(Data())) { error in
            if let error = error {
                print("Ping发送失败: \(error.localizedDescription)")
                // 此处可触发重连逻辑
            }
        }
    }
}

3. 适配苹果后台限制

  • 后台任务断言有效时间有限(通常几分钟),若需长期保持连接,建议结合静默远程通知:服务器有消息时发送静默通知唤醒App,此时可重新建立连接或处理消息。
  • 优先使用wss://加密协议,明文ws://连接更容易被系统在后台断开。
  • 连接断开时避免频繁重连,可加入指数退避机制(如10秒、20秒、40秒递增),防止被系统判定为滥用。

4. 代理回调处理连接异常

实现URLSessionWebSocketDelegate的断开回调,及时处理重连:

func webSocketTask(_ task: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
    print("WebSocket连接断开: \(closeCode.rawValue)")
    // 后台状态下尝试重连(需确保有后台任务时间)
    if UIApplication.shared.applicationState == .background {
        if backgroundTaskID != .invalid {
            connectWebsocket()
        }
    } else {
        connectWebsocket()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 23:30:10