我正在做一个KotlinMultiplatform移动的(KMM)项目,我正在使用WebSockets发送和接收消息。我已经为WebSocket客户端实现了一个类WsChat
,它在Android上可以正常工作,但在iOS上不行。
下面是WsChat
的代码:
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 initRecieve: (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.IO)
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
initRecieve(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() {
scope.cancel()
client.close()
}
}
字符串
这段代码在Android平台上运行良好,但在iOS上不起作用。当我运行iOS应用程序时,错误在下面。
> Task :shared:compileKotlinIosSimulatorArm64 FAILED
e: WsChat.kt:26:52 Unresolved reference: IO
型
我怀疑这可能与iOS中不同的线程模型有关,或者与KMM或协程中的一些细微差别有关,我可能没有意识到。有没有人知道为什么会发生这种情况,以及我如何解决它?
如果你能帮忙的话,我将不胜感激。提前感谢!
1条答案
按热度按时间i7uq4tfw1#
检查Dispatchers.IO的文档,您可以看到它仅在JVM平台上可用,因此在iOS目标上没有解析的引用。您应该在iOS上使用其他调度程序。顺便说一句,在使用Ktor时不需要使用特殊的调度程序,因为我相信它在内部使用自己的线程池,并且应该可以安全地从任何线程使用。
除此之外,你有点幸运,这在Android上工作。
你捕捉会话的方式是非正统的。这个
client.webSocket(...) { }
的重载在块到达末尾时关闭会话,所以代码只工作,因为你碰巧在监听incoming
通道,直到它被关闭,而这发生在块内部,实际上只允许外部关闭会话,而永远不会到达块的末尾。(另外,您并不真正使用private var session
属性,仅使用promise FYI。相反,您可能应该使用webSocketSession函数。这一个返回会话,当你不再需要它时,你可以关闭它。这将更清楚地说明会话何时结束,以及为什么可以在
send
函数中使用它。请参见此处的示例:https://github.com/joffrey-bion/krossbow/blob/main/krossbow-websocket-ktor/src/commonMain/kotlin/org/hildan/krossbow/websocket/ktor/KtorWebSocketClient.kt的