Ktor: Add WebSocket support for the iOS

Created on 25 May 2020  路  12Comments  路  Source: ktorio/ktor

Ktor Version and Engine Used (client or server and name)
Using io.ktor:ktor-client-ios:1.3.2

Describe the bug
This code prints kotlin.IllegalStateException: [generateNonce] is not supported on iOS:

  GlobalScope.launch {
    try {
      HttpClient {
        install(WebSockets)
      }.wss(
        host = "websocketstest.com",
        path = "/service"
      ) {
        send(Frame.Text("timer"))
        for (frame in incoming)
          println((frame as Frame.Text).readText())
      }
    } catch (e: Exception) {
      println(e)
    }
  }

Looks like someone tried to fix this here: https://github.com/ktorio/ktor/pull/1535

feature triaged

All 12 comments

Hi @Hixie, the WebSocket is unsupported on the iOS for now.

Hello, any update on this? I notice there's a PR that got stale https://github.com/ktorio/ktor/pull/1535

I tried to use that code and it worked up to the point where I got another error

io.ktor.client.call.NoTransformationFoundException: No transformation found: class io.ktor.utils.io.ByteChannelNative -> class io.ktor.client.features.websocket.DefaultClientWebSocketSession
with response from wss://javascript.info/article/websocket/chat/ws:
status: 101 Switching Protocols
response headers: 
CF-Cache-Status: DYNAMIC
, Server: cloudflare
, CF-RAY: 5a042751df0be0fa-IAD
, Upgrade: websocket
, cf-request-id: 033676e7230000e0fa31210200000001
, Sec-WebSocket-Accept: Dx6gENctpo2lUPMOWA1N7wLwcfE=
, Date: Mon, 08 Jun 2020 16:57:44 GMT
, alt-svc: h3-27=":443"; ma=86400
, Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
, Connection: upgrade

        at 0   iosApp                              0x0000000107ad340e kfun:kotlin.Throwable.<init>()kotlin.Throwable + 62
        at 1   iosApp                              0x0000000107ac5f87 kfun:kotlin.Exception.<init>()kotlin.Exception + 55
        at 2   iosApp                              0x0000000107ac61a7 kfun:kotlin.RuntimeException.<init>()kotlin.RuntimeException + 55
        at 3   iosApp                              0x0000000107ac6a07 kfun:kotlin.UnsupportedOperationException.<init>()kotlin.UnsupportedOperationException + 55
        at 4   iosApp                              0x0000000108721576 kfun:io.ktor.client.call.NoTransformationFoundException.<init>(io.ktor.client.statement.HttpResponse;kotlin.reflect.KClass<#STAR>;kotlin.reflect.KClass<#STAR>)io.ktor.client.call.NoTransformationFoundException + 678
        at 5   iosApp                              0x000000010871e997 kfun:io.ktor.client.call.HttpClientCall.$receiveCOROUTINE$5.invokeSuspend(kotlin.Result<kotlin.Any?>)kotlin.Any? + 2775
        at 6   iosApp                              0x000000010871ed80 kfun:io.ktor.client.call.HttpClientCall.receive(io.ktor.client.call.TypeInfo)kotlin.Any + 320
        at 7   iosApp                              0x000000010877a621 kfun:io.ktor.client.features.websocket.$webSocketCOROUTINE$49.invokeSuspend(kotlin.Result<kotlin.Any?>)kotlin.Any? + 5729
        at 8   iosApp                              0x0000000107aff568 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 712
        at 9   iosApp                              0x000000010864a8a6 kfun:io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith#internal + 950
        at 10  iosApp                              0x000000010864a45a kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1658
        at 11  iosApp                              0x000000010864c5f9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.object-1.resumeWith#internal + 377
        at 12  iosApp                              0x0000000107aff849 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1449
        at 13  iosApp                              0x000000010864a8a6 kfun:io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith#internal + 950
        at 14  iosApp                              0x000000010864a45a kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1658
        at 15  iosApp                              0x000000010864c5f9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.object-1.resumeWith#internal + 377
        at 16  iosApp                              0x0000000107aff849 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1449
        at 17  iosApp                              0x000000010864a8a6 kfun:io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith#internal + 950
        at 18  iosApp                              0x000000010864a45a kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1658
        at 19  iosApp                              0x000000010864c5f9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.object-1.resumeWith#internal + 377
        at 20  iosApp                              0x0000000107aff849 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1449
        at 21  iosApp                              0x000000010864a8a6 kfun:io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith#internal + 950
        at 22  iosApp                              0x000000010864a45a kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1658
        at 23  iosApp                              0x000000010864c5f9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.object-1.resumeWith#internal + 377
        at 24  iosApp                              0x0000000107aff849 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1449
        at 25  iosApp                              0x000000010864a8a6 kfun:io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith#internal + 950
        at 26  iosApp                              0x000000010864a45a kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1658
        at 27  iosApp                              0x000000010864c5f9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.object-1.resumeWith#internal + 377
        at 28  iosApp                              0x0000000107aff849 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1449
        at 29  iosApp                              0x0000000108460cc3 kfun:kotlinx.coroutines.DispatchedTask.run() + 2627

Hi @Hixie, the fix is in the master for the nonce class, but there is no WebSocket support for ktor-ios.

Hi @e5l, Yes you're right, I noticed it after reading the code, even tho the nonce fix is needed, and the PR looks good, any reason to not merge it?. For the WebSocket support, is possible to modify IosClientEngine to use NSURLSessionWebSocketTask for upgrade request, or be able to use CIO client in MPP (Not possible right now since it uses java classes directly). What should be the best approach?

@e5l so latest ktor 1.3.2 still don't have websocket implementation on the IOS?

Yep. We're waiting for native multithreaded coroutines support

Looks like native multithreaded support almost here :)

https://github.com/kotlin/kotlinx.coroutines/issues/462#issuecomment-645206475

Weirdly, I am getting this exception (kotlin.IllegalStateException: [generateNonce] is not supported on iOS) using io.ktor:ktor-client-curl:1.3.2-1.4-M2, running on linux

Digging into Kotlin Native code, I guess POSIX in general is not supported

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

@e5l Hey, any updates on this?

@e5l yes, please update, we are so excited about websocket support for iOS!

Was this page helpful?
0 / 5 - 0 ratings