When developing a Kotlin Multiplatform/Ktor application that uses WebSockets for Android (or for other platform!), we might run into this exception:
Connection error: java.lang.IllegalArgumentException: Engine doesn't support WebSocketCapability
at io.ktor.client.engine.HttpClientEngine$DefaultImpls.checkExtensions(HttpClientEngine.kt:105)
at io.ktor.client.engine.HttpClientEngine$DefaultImpls.access$checkExtensions(HttpClientEngine.kt:24)
at io.ktor.client.engine.HttpClientEngine$install$1.invokeSuspend(HttpClientEngine.kt:68)
at io.ktor.client.engine.HttpClientEngine$install$1.invoke(Unknown Source:15)
at io.ktor.client.engine.HttpClientEngine$install$1.invoke(Unknown Source:4)
TL;DR:
- Most likely you miss the http engine dependency for the android part (or other platform).
- Or you need to switch http engine for one that supports WebSockets. Useful table to compare engines: https://ktor.io/docs/client-engines.html#limitations.
okhttp
is one of the engines that works both with Android and WebSockets. If you target other platform, look at the link from above.
kotlin {
sourceSets {
androidMain.dependencies {
implementation("io.ktor:ktor-client-okhttp:${ktor}}")
}
}
}
To be able to understand the root of the problem, we need to look at how http client works in Kotlin Multiplatform application. Consider this:
- Shared code. Usually it should contain http client interfaces only, without implementation/http engine. Dependency to include to the shared code:
io.ktor:ktor-client-core:${ktor}
. - Specific platform. It should contain implementation dependency for the http engine.
- Can be okhttp for Android module:
io.ktor:ktor-client-okhttp:${ktor}
. - Can be cio for Dekstop module:
io.ktor:ktor-client-cio:${ktor}
. - Can be darwin for IOS module:
io.ktor:ktor-client-darwin:${ktor}
.
- Can be okhttp for Android module:
In the shared code we can have something like this:
private val client = HttpClient {
install(WebSockets)
}
In this code, we just initiate basic http client and add WebSocket support. However, the actual client (engine) depends on the platform! And it depends on the library we use. The code from above uses just high-level interfaces.
So when you encounter a case when you have this high-level code in the app, but doesn’t include http engine dependency, it throws an error “Engine doesn’t support WebSocketCapability”.
For the general knowledge, shared code for http client initialization is very limited in its capabilities. For example, we can’t set up SSL custom configuration, since it’s platform-dependent, therefore if we need to have ability to configure custom SSL, we need to use expected/actual mechanism. Look at the very good example here.
Telegram channel
If you still have any questions, feel free to ask me in the comments under this article or write me at promark33@gmail.com.
If I saved your day, you can support me 🤝