Skip to main content
Version: 4.5.x

SocketX Client for Android

Latest Release

Introduction

This Android library provides the Eclypses SocketX Mobile Client for Android. It enables secure, persistent WebSocket communication between your Android app and your backend services via a SocketX server. You must have licensed access to a SocketX server instance. More Info

Purpose of SocketX:

  • Establish persistent, encrypted WebSocket tunnels to your server
  • Protect real-time data with MTE encryption
  • Support bidirectional messaging with automatic encryption/decryption
  • Enable secure pub/sub and room-based communication patterns

Documentation

📚 Complete README with Java Examples - Comprehensive documentation with detailed Java and Kotlin examples, troubleshooting, and API reference

💡 This quick-start guide provides Kotlin examples for experienced Android developers. For Java examples, detailed troubleshooting, and comprehensive documentation, see the GitHub README.

Prerequisites

  • Android 8.0 (API 26) or later - Required for modern WebSocket support and cryptographic capabilities
  • Kotlin 1.9+ / Java 8+ - Library is Kotlin-based but fully Java-compatible
  • OkHttp 4.12.0 or later - Library wraps OkHttp WebSocket implementation
  • Access to a licensed SocketX server instance - Server URL and proper licensing credentials required

How SocketX Works

Traditional WebSocket (Unencrypted):

[Your Android App] ←→ WebSocket ←→ [Your Backend Server]
⚠️ Data transmitted in plaintext (even with WSS/TLS, data is visible at endpoints)

With SocketX (MTE-Encrypted):

[Your Android App] ←→ Encrypted WebSocket Tunnel ←→ [SocketX Server] ←→ [Your Backend Service]
↑ ↑
Encrypts here Decrypts & forwards here

Data Flow:

  1. Pairing: Automatic MTE pairing handshake using post-quantum Kyber-512 key exchange
  2. Encode: Data encrypted using MTE before transmission
  3. Tunnel: Encrypted payload travels over WebSocket to SocketX server
  4. Decode: Server decrypts payload using paired MTE decoder
  5. Forward: Server forwards original data to designated backend service or room
  6. Response: Response follows same path in reverse

Key Benefits:

  • End-to-end encryption that's quantum-resistant (Kyber-512)
  • Zero-trust architecture - data encrypted before leaving your app
  • Persistent connections for real-time, low-latency messaging
  • Automatic reconnection and pairing management

Installation

Kotlin DSL (build.gradle.kts):

dependencies {
implementation("com.eclypses:socketx-client-android:1.0.8")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
}

Groovy DSL (build.gradle):

dependencies {
implementation 'com.eclypses:socketx-client-android:1.0.8'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}

Quick Start

1. Add Internet Permission

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />

2. Basic Implementation

import okhttp3.*
import okio.ByteString.Companion.toByteString
import com.eclypses.socketx_client_android.SocketXClient
import com.eclypses.socketx_client_android.SocketXError

class ChatManager(private val serverUrl: String, private val roomPath: String) {
private var okHttpClient: OkHttpClient? = null
private var socketXClient: SocketXClient? = null
private var webSocket: WebSocket? = null
var isConnected = false

fun connect() {
// 1. Configure OkHttp client with custom settings
okHttpClient = OkHttpClient.Builder()
.pingInterval(20, TimeUnit.SECONDS)
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.header("Authorization", "Bearer your-token")
.build()
chain.proceed(request)
}
.build()

// 2. Create SocketX factory (wraps OkHttp client)
socketXClient = SocketXClient(okHttpClient!!)

// 3. Build WebSocket request
val request = Request.Builder()
.url("$serverUrl$roomPath")
.build()

// 4. Create WebSocket listener
val listener = object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
// Called after MTE handshake completes
isConnected = true
println("✅ Connected and paired")
}

override fun onMessage(webSocket: WebSocket, text: String) {
// Automatically decrypted
println("📨 Received: $text")
}

override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
// Automatically decrypted
println("📦 Received: ${bytes.size} bytes")
}

override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
isConnected = false
when (t) {
is SocketXError.HandshakeError -> println("❌ Handshake failed")
is SocketXError.CodecError -> println("❌ Encryption error")
is SocketXError.NetworkError -> println("❌ Network error")
}
}
}

// 5. Create secure WebSocket (automatically encrypts/decrypts)
webSocket = socketXClient!!.newWebSocket(request, listener)
}

fun sendMessage(text: String) {
webSocket?.send(text) // Automatically encrypted
}

fun sendBinary(data: ByteArray) {
webSocket?.send(data.toByteString()) // Automatically encrypted
}

fun disconnect() {
webSocket?.close(1000, "Goodbye")
isConnected = false
}
}

Java Developers: See the GitHub README for complete Java examples.

3. Usage in Activity

class ChatActivity : AppCompatActivity() {
private lateinit var chatManager: ChatManager

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

chatManager = ChatManager("wss://your-server.com", "/chat-room-1")
chatManager.connect()

sendButton.setOnClickListener {
chatManager.sendMessage(messageEditText.text.toString())
}
}

override fun onDestroy() {
super.onDestroy()
chatManager.disconnect()
}
}

Usage Examples

Sending Messages

Text Messages:

// Simple text
webSocket?.send("Hello, World!")

// JSON
val json = JSONObject().apply {
put("type", "chat")
put("message", "Hello")
}.toString()
webSocket?.send(json)

Binary Data:

// Image
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.photo)
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream)
webSocket?.send(stream.toByteArray().toByteString())

// File
val fileData = File("/path/to/file.pdf").readBytes()
webSocket?.send(fileData.toByteString())

Receiving Messages

Text Messages:

override fun onMessage(webSocket: WebSocket, text: String) {
// Parse JSON
val json = JSONObject(text)
val messageType = json.getString("type")
val content = json.getString("message")

runOnUiThread {
// Update UI
}
}

Binary Data:

override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
val data = bytes.toByteArray()

// Display image
val bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)
runOnUiThread {
imageView.setImageBitmap(bitmap)
}
}

Room-Based Communication

// Connect to different rooms
val chatManager = ChatManager("wss://server.com", "/chat/general")
val notificationManager = ChatManager("wss://server.com", "/notifications/user123")

chatManager.connect()
notificationManager.connect()

// Messages sent to each room are isolated
chatManager.sendMessage("Hello to chat room")
notificationManager.sendMessage("Status update")

URL Path Examples:

  • /chat/general - General chat room
  • /notifications/user123 - User-specific notifications
  • /game/match-456 - Game-specific room
  • /stream/video-1 - Streaming channel

Error Handling

Error Types

sealed class SocketXError : Throwable() {
class HandshakeError(message: String) : SocketXError() // MTE pairing failed
class CodecError(message: String) : SocketXError() // Encryption/decryption error
class NetworkError(message: String) : SocketXError() // Connection error
class InternalError(message: String) : SocketXError() // License/config error
}

Comprehensive Error Handling

override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
when (t) {
is SocketXError.HandshakeError -> {
// MTE pairing failed - check server configuration
Log.e(TAG, "Handshake failed: ${t.message}")
}
is SocketXError.CodecError -> {
// Encryption error - reconnect to re-pair
Log.e(TAG, "Codec error: ${t.message}")
scheduleReconnect()
}
is SocketXError.NetworkError -> {
// Network issue - check connectivity
Log.e(TAG, "Network error: ${t.message}")
if (isNetworkAvailable()) {
scheduleReconnect()
}
}
is SocketXError.InternalError -> {
// Configuration issue - check MTE license
Log.e(TAG, "Internal error: ${t.message}")
}
}
}

Advanced Configuration

Custom OkHttp Configuration

val okHttpClient = OkHttpClient.Builder()
// Timeouts
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)

// Keep-alive
.pingInterval(20, TimeUnit.SECONDS)

// Custom headers
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.header("Authorization", "Bearer $token")
.header("X-API-Key", apiKey)
.build()
chain.proceed(request)
}

// Certificate pinning
.certificatePinner(
CertificatePinner.Builder()
.add("your-domain.com", "sha256/AAAA...")
.build()
)

// Retry on failure
.retryOnConnectionFailure(true)

.build()

val socketXClient = SocketXClient(okHttpClient)

Connection Lifecycle Management

class ChatManager {
private val handler = Handler(Looper.getMainLooper())
private var reconnectAttempts = 0
private val maxReconnectAttempts = 5

private fun scheduleReconnect() {
if (reconnectAttempts >= maxReconnectAttempts) {
Log.e(TAG, "Max reconnect attempts reached")
return
}

val delay = (2.0.pow(reconnectAttempts) * 1000).toLong() // Exponential backoff
reconnectAttempts++

handler.postDelayed({
connect()
}, delay)
}

override fun onOpen(webSocket: WebSocket, response: Response) {
reconnectAttempts = 0 // Reset on success
isConnected = true
}
}

Background Connection Management

class ChatService : Service() {
private lateinit var chatManager: ChatManager

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// Create foreground notification
val notification = createNotification()
startForeground(NOTIFICATION_ID, notification)

// Connect
chatManager.connect()

return START_STICKY
}

override fun onDestroy() {
super.onDestroy()
chatManager.disconnect()
}
}

Troubleshooting

Connection Issues

Problem: Connection fails immediately

✅ Verify URL format: wss://your-server.com/room (not https://)
✅ Check network permissions in AndroidManifest.xml
✅ Ensure server is running and accessible
✅ Test with wscat -c wss://your-server.com/test

Problem: Handshake error during connection

✅ Verify MTE license is valid
✅ Check server MTE configuration
✅ Review server logs for rejection reasons

Problem: Works in emulator but not on device

✅ Check device network connectivity
✅ Verify server URL is accessible (not localhost)
✅ Review certificate pinning if configured

Message Issues

Problem: Messages not received by server

✅ Verify connection before sending (isConnected)
✅ Check server logs
✅ Verify correct room path

Problem: Cannot receive messages

✅ Set up callbacks before calling connect()
✅ Ensure messages are sent to correct room

Problem: Codec errors

✅ Disconnect and reconnect to re-establish pairing
✅ Verify compatible MTE versions
✅ Check for data corruption

Performance Issues

Problem: High memory usage

✅ Don't accumulate messages indefinitely (limit collection size)
✅ Process binary data immediately
✅ Disconnect when not needed

Problem: Connection drops in background

✅ Normal Android behavior - apps suspended in background
✅ Use foreground service for persistent connections
✅ Reconnect in onResume()

API Reference

SocketXClient

Constructor:

SocketXClient(client: OkHttpClient)

Creates a factory for secure WebSocket connections. Validates MTE licensing.

Throws: SocketXError.InternalError if MTE license validation fails


Method:

fun newWebSocket(request: Request, listener: WebSocketListener): WebSocket

Creates a secure WebSocket wrapper that:

  • Uses provided OkHttpClient for underlying connection
  • Automatically performs MTE pairing handshake
  • Transparently encrypts/decrypts all messages
  • Calls onOpen AFTER handshake completes

Returns: WebSocket instance with MTE encryption


WebSocket (Standard OkHttp)

fun send(text: String): Boolean          // Send text (auto-encrypted)
fun send(bytes: ByteString): Boolean // Send binary (auto-encrypted)
fun close(code: Int, reason: String?) // Close connection
fun cancel() // Immediately release resources

WebSocketListener Callbacks

onOpen(webSocket: WebSocket, response: Response)
// Called after MTE handshake completes

onMessage(webSocket: WebSocket, text: String)
// Received text message (auto-decrypted)

onMessage(webSocket: WebSocket, bytes: ByteString)
// Received binary data (auto-decrypted)

onClosing(webSocket: WebSocket, code: Int, reason: String)
// Remote peer initiated shutdown

onClosed(webSocket: WebSocket, code: Int, reason: String)
// Connection fully closed

onFailure(webSocket: WebSocket, t: Throwable, response: Response?)
// Error occurred (check SocketXError types)

Contact Eclypses

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


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