From 45766621f2dced38076a6c92a17feb56569ad99e Mon Sep 17 00:00:00 2001 From: Somasundaram Mahesh Date: Wed, 18 Feb 2026 18:49:14 +0530 Subject: [PATCH] fix(android): switch Ktor CIO engine to OkHttp for stable background WebSocket CIO uses Java NIO selectors which Android's power management freezes when the app is backgrounded, dropping the WebSocket connection. OkHttp is Android-native and maintains connections through the OS network stack. --- android/app/build.gradle.kts | 2 +- .../thisux/droidclaw/connection/ReliableWebSocket.kt | 12 ++---------- android/gradle/libs.versions.toml | 2 +- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 3150bcd..5b540ce 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -48,7 +48,7 @@ dependencies { implementation(libs.androidx.compose.material3) // Ktor WebSocket - implementation(libs.ktor.client.cio) + implementation(libs.ktor.client.okhttp) implementation(libs.ktor.client.websockets) implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.serialization.kotlinx.json) diff --git a/android/app/src/main/java/com/thisux/droidclaw/connection/ReliableWebSocket.kt b/android/app/src/main/java/com/thisux/droidclaw/connection/ReliableWebSocket.kt index f3dab02..7e8d434 100644 --- a/android/app/src/main/java/com/thisux/droidclaw/connection/ReliableWebSocket.kt +++ b/android/app/src/main/java/com/thisux/droidclaw/connection/ReliableWebSocket.kt @@ -6,8 +6,7 @@ import com.thisux.droidclaw.model.ConnectionState import com.thisux.droidclaw.model.DeviceInfoMsg import com.thisux.droidclaw.model.ServerMessage import io.ktor.client.HttpClient -import io.ktor.client.engine.cio.CIO -import io.ktor.client.engine.cio.endpoint +import io.ktor.client.engine.okhttp.OkHttp import io.ktor.client.plugins.websocket.WebSockets import io.ktor.client.plugins.websocket.webSocket import io.ktor.websocket.Frame @@ -78,14 +77,7 @@ class ReliableWebSocket( } private suspend fun connectOnce(serverUrl: String, apiKey: String, deviceInfo: DeviceInfoMsg) { - val httpClient = HttpClient(CIO) { - engine { - requestTimeout = 30_000 - endpoint { - connectTimeout = 10_000 - keepAliveTime = 30_000 - } - } + val httpClient = HttpClient(OkHttp) { install(WebSockets) { pingIntervalMillis = 30_000 } diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 3295033..fd7f33e 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -31,7 +31,7 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } -ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" } +ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor" } ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", version.ref = "ktor" } ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }