Как реализовать восстановление WebSocket-соединения при переходе приложения из фона в активное состояние?

«Как реализовать восстановление WebSocket-соединения при переходе приложения из фона в активное состояние?» — вопрос из категории Сети, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Восстановление соединения требует отслеживания жизненного цикла приложения и реализации логики переподключения с обработкой ошибок.

Основная стратегия:

  1. Отслеживание изменения состояния: Подпишитесь на уведомления о переходе приложения в активное состояние.

    // В AppDelegate или SceneDelegate
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(appDidBecomeActive),
        name: UIApplication.didBecomeActiveNotification,
        object: nil
    )
  2. Метод переподключения: Реализуйте метод, который безопасно закрывает старое соединение и устанавливает новое.

    class WebSocketManager {
        private var webSocketTask: URLSessionWebSocketTask?
        private let session: URLSession
    
        init() {
            self.session = URLSession(configuration: .default)
        }
    
        func reconnect() {
            // 1. Корректно закройте предыдущее соединение
            webSocketTask?.cancel(with: .goingAway, reason: nil)
    
            // 2. Создайте новую задачу
            let url = URL(string: "wss://yourserver.com/socket")!
            webSocketTask = session.webSocketTask(with: url)
    
            // 3. Запустите задачу и начните слушать сообщения
            webSocketTask?.resume()
            listenForMessages()
        }
    
        private func listenForMessages() {
            webSocketTask?.receive { [weak self] result in
                switch result {
                case .success(let message):
                    // Обработайте сообщение
                    self?.listenForMessages() // Продолжите слушать
                case .failure(let error):
                    print("WebSocket receive error: (error)")
                    // Запланируйте повторное подключение с задержкой
                    self?.scheduleReconnect()
                }
            }
        }
    
        @objc private func appDidBecomeActive() {
            // Проверьте состояние сети перед переподключением
            if NetworkMonitor.shared.isConnected {
                reconnect()
            }
        }
    }
  3. Улучшение логики переподключения:

    • Экспоненциальная задержка: Добавьте увеличивающуюся задержку между попытками, чтобы не нагружать сервер.
    • Проверка сети: Используйте Network.framework (NWPathMonitor) для проверки доступности сети перед попыткой соединения.
    • Фоновый режим: Для поддержания соединения в фоне добавьте capability Background Modes → Voice over IP или используйте BGProcessingTask для периодического "пинга", но учитывайте строгие ограничения iOS.

Важно: WebSocket-соединение, разорванное системой при переходе в фон, не может быть автоматически восстановлено тем же объектом URLSessionWebSocketTask. Необходимо создавать новую задачу.