Skip to main content

SocketX Client for iOS using Swift

Latest Release

Introduction​

This Swift Package provides the Eclypses SocketX Client for iOS. It enables secure, encrypted WebSocket communication between your iOS app and your backend via a SocketX server. All messages are automatically protected using MTE (Microtokenization) encryption with Kyber-512 post-quantum key exchange.

Purpose of SocketX Client:

  • Establish secure WebSocket connections to SocketX servers
  • Send and receive encrypted text and binary messages
  • Support room-based pub/sub messaging patterns
  • Automatic MTE pairing and encryption/decryption
Comprehensive Documentation

This guide provides a quick-start for experienced developers. For detailed examples, troubleshooting, and in-depth explanations, see the complete documentation on GitHub.

Prerequisites​

  • iOS 14.0 or later
  • Swift 5.5 or later
  • Xcode 13.0 or later
  • Access to a SocketX server instance

Installation​

  1. In Xcode, go to File > Add Packages...
  2. Enter the package URL: https://github.com/Eclypses/socketx-client-swift.git
  3. Follow the prompts to add the package to your project.

Setup​

  1. Import the SocketX module:
import SocketXClient
  1. Create a WebSocket task and initialize the SocketX client:
class ChatManager {
var socketXClient: SocketXClient?
var isConnected = false

func setupConnection() {
// 1. Create URL for the room you want to join
let url = URL(string: "wss://your-server.com/chat/room-1")!

// 2. Configure URLSession
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)

// 3. Create WebSocket task (do NOT call .resume())
let task = session.webSocketTask(with: url)

// 4. Initialize SocketX client
do {
socketXClient = try SocketXClient(task: task)
setupCallbacks()
} catch {
print("Failed to initialize: \(error)")
}
}

func setupCallbacks() {
socketXClient?.onConnected = { [weak self] in
self?.isConnected = true
print("✅ Connected and ready")
}

socketXClient?.onMessageReceived = { [weak self] text in
print("📨 Received: \(text)")
self?.handleMessage(text)
}

socketXClient?.onBinaryReceived = { [weak self] data in
print("📦 Received: \(data.count) bytes")
self?.handleBinaryData(data)
}

socketXClient?.onError = { [weak self] error in
self?.isConnected = false
print("❌ Error: \(error)")
}
}

func handleMessage(_ text: String) {
// Process received text message
}

func handleBinaryData(_ data: Data) {
// Process received binary data
}
}

Usage​

Connecting​

socketXClient?.connect()

The client will automatically:

  1. Establish the WebSocket connection
  2. Perform MTE pairing with the server (Kyber-512 key exchange)
  3. Join the specified room
  4. Trigger onConnected when ready

Sending Messages​

Text Messages:

// Plain text
socketXClient?.send(text: "Hello, World!")

// JSON
let message = ["type": "chat", "content": "Hello"]
if let jsonData = try? JSONSerialization.data(withJSONObject: message),
let jsonString = String(data: jsonData, encoding: .utf8) {
socketXClient?.send(text: jsonString)
}

// Codable objects
struct ChatMessage: Codable {
let type: String
let content: String
}

let message = ChatMessage(type: "chat", content: "Hello")
if let jsonData = try? JSONEncoder().encode(message),
let jsonString = String(data: jsonData, encoding: .utf8) {
socketXClient?.send(text: jsonString)
}

Binary Data:

// Send binary data
let data = Data([0x01, 0x02, 0x03])
socketXClient?.send(binary: data)

// Send image
if let image = UIImage(named: "photo"),
let imageData = image.jpegData(compressionQuality: 0.8) {
socketXClient?.send(binary: imageData)
}

Receiving Messages​

Set up callbacks before connecting:

socketXClient?.onMessageReceived = { text in
// Parse JSON
if let data = text.data(using: .utf8),
let message = try? JSONDecoder().decode(ChatMessage.self, from: data) {
print("Message: \(message.content)")
}
}

socketXClient?.onBinaryReceived = { data in
// Display image
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self.imageView.image = image
}
}
}

Room-Based Messaging​

The SocketX server routes messages based on the URL path:

// Join different rooms
let chatUrl = URL(string: "wss://your-server.com/chat/general")!
let notificationsUrl = URL(string: "wss://your-server.com/notifications/user-123")!

// Each room has its own client instance
let chatClient = try? SocketXClient(task: session.webSocketTask(with: chatUrl))
let notificationClient = try? SocketXClient(task: session.webSocketTask(with: notificationsUrl))

Messages sent to a room are received by all connected clients in that room.

Disconnecting​

socketXClient?.disconnect()
socketXClient = nil

Error Handling​

socketXClient?.onError = { error in
switch error {
case .codecError(let reason):
// MTE encryption/decryption error
// Usually resolved by reconnecting
print("Codec error: \(reason)")

case .networkError(let reason):
// Network connectivity issue
print("Network error: \(reason)")
}
}

SwiftUI Integration​

import SwiftUI
import SocketXClient

class ChatViewModel: ObservableObject {
@Published var messages: [String] = []
@Published var isConnected = false

private var socketXClient: SocketXClient?

func connect() {
let url = URL(string: "wss://dev-socketx-server.eclypses.com/chat")!
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.webSocketTask(with: url)

socketXClient = try? SocketXClient(task: task)

socketXClient?.onConnected = { [weak self] in
DispatchQueue.main.async {
self?.isConnected = true
}
}

socketXClient?.onMessageReceived = { [weak self] text in
DispatchQueue.main.async {
self?.messages.append(text)
}
}

socketXClient?.onError = { [weak self] error in
DispatchQueue.main.async {
self?.isConnected = false
}
}

socketXClient?.connect()
}

func send(_ message: String) {
socketXClient?.send(text: message)
}

func disconnect() {
socketXClient?.disconnect()
socketXClient = nil
isConnected = false
}
}

struct ChatView: View {
@StateObject private var viewModel = ChatViewModel()
@State private var messageText = ""

var body: some View {
VStack {
List(viewModel.messages, id: \.self) { message in
Text(message)
}

HStack {
TextField("Message", text: $messageText)
.textFieldStyle(RoundedBorderTextFieldStyle())

Button("Send") {
viewModel.send(messageText)
messageText = ""
}
.disabled(!viewModel.isConnected)
}
.padding()
}
.onAppear { viewModel.connect() }
.onDisappear { viewModel.disconnect() }
}
}

Demo Server​

A public demo server is available for testing:

let url = URL(string: "wss://dev-socketx-server.eclypses.com/test")!

Available rooms:

  • /dogs, /cats, /fish - Text messaging rooms
  • /bytes-1, /bytes-2 - Binary messaging rooms

API Reference​

See the complete API documentation for full details. Key classes:

  • SocketXClient: Main entry point for WebSocket communication

    • init(task: URLSessionWebSocketTask) throws
    • connect() - Establish connection and perform MTE pairing
    • disconnect() - Close connection
    • send(text: String) - Send encrypted text message
    • send(binary: Data) - Send encrypted binary data
  • Callbacks:

    • onConnected: (() -> Void)? - Called when connection is ready
    • onMessageReceived: ((String) -> Void)? - Called when text message received
    • onBinaryReceived: ((Data) -> Void)? - Called when binary data received
    • onError: ((SocketXClientError) -> Void)? - Called on errors
  • SocketXClientError: Error types

    • codecError(String) - MTE encryption/decryption error
    • networkError(String) - Network connectivity error

Support​

Email: info@eclypses.com
Web: www.eclypses.com

Additional Resources​

For detailed examples, troubleshooting, and advanced implementation patterns:


All trademarks of Eclypses Inc. may not be used without Eclypses Inc.'s prior written consent.