KMM项目WebSocket代码Android正常,iOS报Unresolved reference: IO错误
问题原因
编译错误Unresolved reference: IO的核心原因是:Dispatchers.IO是JVM平台专属的协程调度器,Kotlin/Native(iOS目标平台)的协程库并没有提供这个调度器实现,因此在KMM的common模块代码中直接引用会导致iOS编译失败。
解决方法
1. 替换为多平台兼容的调度器
把Dispatchers.IO替换成跨平台通用的Dispatchers.Default,同时建议搭配SupervisorJob()创建协程作用域——这样单个子协程出现异常时,不会导致整个作用域被取消,更适合WebSocket这类长连接场景:
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
Dispatchers.Default在iOS和Android平台都有稳定实现,既能处理IO密集型任务,也能应对计算密集型场景,完全可以替代Dispatchers.IO的跨平台需求。
2. 额外代码优化
- 修正拼写错误:把参数
initRecieve改成initReceive,保持命名一致性 - 完善关闭逻辑:先关闭WebSocket会话再关闭客户端,避免资源泄漏:
fun close() { scope.launch { session?.close(CloseReason(CloseReason.Codes.NORMAL, "Client closed session")) } scope.cancel() client.close() }
- 确认依赖:在common模块的
build.gradle.kts中,确保引入了多平台协程核心依赖:
sourceSets { val commonMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // 其他依赖... } } }
修正后的完整代码
import com.bokutotu.dateappmobile.model.* import io.ktor.client.* import io.ktor.client.plugins.websocket.* import io.ktor.http.* import io.ktor.websocket.* import kotlinx.coroutines.* import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json expect fun wsClient(url: String, config: HttpClientConfig<*>.() -> Unit = {}): HttpClient class WsChat( private val host: String = "127.0.0.1", private val port: Int = 8080, private val chatId: Int, private val userId: Int, private val initReceive: (String) -> Unit, private val onReceive: (String) -> Unit ) { private val client = wsClient(host) private var session: DefaultClientWebSocketSession? = null private val sessionPromise = CompletableDeferred<DefaultClientWebSocketSession?>() private var initialMessageReceived = false // 替换为多平台兼容的协程作用域 private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) init { scope.launch { initSession() } } private suspend fun initSession() { client.webSocket( method = HttpMethod.Get, host = host, port = port, path = "/message/$chatId/$userId" ) { session = this sessionPromise.complete(this) initReceivePipeline() } } private suspend fun initReceivePipeline() { val session = sessionPromise.await() session?.let { for (frame in it.incoming) { frameHandler(frame) { receivedText -> if (!initialMessageReceived) { initialMessageReceived = true initReceive(receivedText) } else { onReceive(receivedText) } println("here") } } } } private fun frameHandler(frame: Frame, receiveFunc: (String) -> Unit) { when (frame) { is Frame.Text -> { val receivedText = frame.readText() receiveFunc(receivedText) } else -> println("Unexpected Frame format") } } fun send(newMessage: NewMessageJson) { val json = Json.encodeToString(newMessage) scope.launch { val session = sessionPromise.await() session?.send(Frame.Text(json)) } } fun close() { // 先关闭WebSocket会话,再取消作用域和客户端 scope.launch { session?.close(CloseReason(CloseReason.Codes.NORMAL, "Client closed session")) } scope.cancel() client.close() } }
内容的提问来源于stack exchange,提问作者musako
相关产品推荐
相关产品推荐

