WebSocket библиотека Swift: Starscream для iOS/macOS

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Starscream — WebSocket библиотека для Swift (iOS/macOS)

Starscream — это легковесная, но мощная библиотека для работы с протоколом WebSocket на платформах Apple. Написана полностью на Swift, не имеет внешних зависимостей и поддерживает iOS, macOS, tvOS и watchOS. Если вам нужно организовать двустороннюю связь в реальном времени между мобильным приложением и сервером (чат, уведомления, онлайн-игры) — Starscream станет отличным выбором.

Основные возможности

  • Полная поддержка стандарта RFC 6455 (WebSocket Protocol).
  • Работа через защищённое соединение wss:// и обычное ws://.
  • Автоматическое переподключение при разрыве соединения.
  • Поддержка фреймов: текст, бинарные данные (Data), пинг/понг.
  • Простая интеграция через CocoaPods, Swift Package Manager или Carthage.
  • Совместимость с Combine (iOS 13+) и Swift Concurrency (async/await).

Установка через Swift Package Manager (рекомендуется)

Добавьте пакет в Xcode: File → Add Packages и вставьте URL репозитория:

https://github.com/daltoniam/Starscream.git

Выберите версию (последнюю стабильную) и добавьте в ваш таргет.

Базовый пример подключения

Создадим простой WebSocket клиент, который подключается к серверу и выводит полученные сообщения.

import Starscream

class WebSocketManager {
    var socket: WebSocket?
    
    func connect() {
        var request = URLRequest(url: URL(string: "wss://echo.websocket.org")!)
        request.timeoutInterval = 5
        socket = WebSocket(request: request)
        socket?.delegate = self
        socket?.connect()
    }
}

extension WebSocketManager: WebSocketDelegate {
    func didReceive(event: WebSocketEvent, client: WebSocket) {
        switch event {
        case .connected(let headers):
            print("Подключено! Заголовки: \(headers)")
        case .disconnected(let reason, let code):
            print("Отключено: \(reason) (код: \(code))")
        case .text(let string):
            print("Получен текст: \(string)")
        case .binary(let data):
            print("Получены бинарные данные: \(data.count) байт")
        case .ping(let data):
            print("Пинг: \(data?.hexString ?? "нет данных")")
        case .pong(let data):
            print("Понг: \(data?.hexString ?? "нет данных")")
        case .viabilityChanged(let isViable):
            print("Соединение активно: \(isViable)")
        case .reconnectSuggested(let shouldReconnect):
            print("Рекомендуется переподключение: \(shouldReconnect)")
        case .cancelled:
            print("Соединение отменено")
        case .error(let error):
            print("Ошибка: \(error?.localizedDescription ?? "неизвестная ошибка")")
        }
    }
}

Отправка данных

Starscream позволяет отправлять как текстовые строки, так и бинарные данные. Пример отправки JSON:

func sendMessage(text: String) {
    let message: [String: Any] = [
        "type": "chat",
        "content": text,
        "timestamp": Int(Date().timeIntervalSince1970)
    ]
    if let jsonData = try? JSONSerialization.data(withJSONObject: message, options: []),
       let jsonString = String(data: jsonData, encoding: .utf8) {
        socket?.write(string: jsonString)
    }
}

// Отправка бинарного файла (например, изображения)
func sendImage(data: Data) {
    socket?.write(data: data)
}

Работа с Combine (iOS 13+)

Для реактивного программирования Starscream предоставляет Publisher:

import Combine

class CombineViewModel: ObservableObject {
    @Published var lastMessage: String = ""
    private var socket: WebSocket?
    private var cancellables = Set<AnyCancellable>()
    
    func setup() {
        var request = URLRequest(url: URL(string: "wss://example.com/ws")!)
        socket = WebSocket(request: request)
        
        socket?.publisher
            .sink { completion in
                print("Завершение: \(completion)")
            } receiveValue: { [weak self] event in
                switch event {
                case .text(let text):
                    self?.lastMessage = text
                default:
                    break
                }
            }
            .store(in: &cancellables)
        
        socket?.connect()
    }
}

Автоматическое переподключение

Starscream не имеет встроенного механизма reconnect, но его легко реализовать самостоятельно:

class ReconnectManager {
    private var socket: WebSocket?
    private var retryDelay: TimeInterval = 1.0
    private let maxRetryDelay: TimeInterval = 30.0
    
    func start() {
        connect()
    }
    
    private func connect() {
        let request = URLRequest(url: URL(string: "wss://example.com")!)
        socket = WebSocket(request: request)
        socket?.delegate = self
        socket?.connect()
    }
}

extension ReconnectManager: WebSocket                    

Рекомендаций