Skip to main content
Version: 4.5.x

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
  • Valid MTE license (configured in Settings.swift)
  • 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.