Skip to main content

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 SocketX server instance - You need the server URL your app will connect to

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 the SocketX server URL and settings
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

✅ Confirm the server's DOMAIN_MAP has an entry matching the host you connect to
✅ Confirm your app's origin is in that entry's allowedOrigins
✅ 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.

Throws: SocketXError.InternalError if the client cannot be initialized


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.