美文网首页互联网科技码农的世界技术干货
[Kotlin/Native] 踩坑,在K/N里使用 Ktor-

[Kotlin/Native] 踩坑,在K/N里使用 Ktor-

作者: 何晓杰Dev | 来源:发表于2019-05-25 22:18 被阅读13次

这个坑还是比较有意思的,主要来说分为以下几种情况:

  1. 编译时报 io.ktor 不存在;
  2. 编译时报 编译器版本不对;
  3. 编译时报 curl/lib 找不到;
  4. 编译时报 _iconv 函数找不到

总共这四种情况,我们一个个来解决。

先说一个前提条件,gradle 必须用 5.4 以上版本,切记!


一、io.ktor 不存在

首先必须确保引用是对的,在 Kotlin/Native 内,引用往往是分段的,如果认为 commonMain 里加了依赖就可以延伸到全部的 Target,这就大错特错了。正确的引用方法是,在 commonMain 里引用 metadata,而在 Target 内引用平台专属的包,如下所示:

sourceSets {
        commonMain {
            dependencies {
                implementation kotlin('stdlib-common')
                implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.2.1'
                implementation 'io.ktor:ktor-client-core:1.2.0'
                implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.11.0'
            }
        }
        macosMain {
            dependencies {
                implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.2.1'
                implementation 'io.ktor:ktor-client-curl:1.2.0'
                implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.11.0'
            }
        }
    }

其中的对应关系一眼就能看出来,在 commonMain 中引用 ktor-client-core,而在 macosMain 内必须引用 ktor-client-curl 才能够完成编译。还记得之前说的 expectactual 吗?这里的依赖原理与它是一致的。

二、编译器版本不对

这个问题是非常大的坑,要解决这个问题,唯一的办法就是把所有的库升级到最新,之前我用 Kotlin 1.3.21,在编译协程库时,就必须对应用 1.1.1 的协程库,然而加入了 ktor-client 后,却发现 ktor-client 不论用哪个版本,都无法与 kotlin 1.3.21Coroutines 1.1.1 完全对应起来,永远都会编译报版本兼容异常。

所以在这种情况下只能升级,把一切都升到最高版本,使用以下命令可以升级 Kotlin 编译器:

$ brew upgrade kotlin

安装完成后,需要确认当前的 Kotlin 编译器版本:

$ kotlin -version
Kotlin version 1.3.31-release-197 (JRE 1.8.0_202-b08)
$ konanc -version
info: kotlinc-native 1.3.31 (JRE 1.8.0_202-b08)
Kotlin/Native: 1.2.1

这两个命令的版本同时正确才可以,不然的话,依然需要进行升级。

升级完毕后,使用以下版本号可以顺利的完成编译:

Kotlin: 1.3.31
Coroutines: 1.2.1
Ktor-Client: 1.2.0
Serialization: 0.11.0

三、curl/lib 找不到

这个问题很好解决,只需要安装 curl 的 library 即可解决,一个命令搞定:

$ brew install curl curl-openssl

安装后在 /usr/local/opt/curl/lib 就会出现链接时需要的库。

四、_iconv 找不到

最后的这个问题,说难不难,说简单也不简单,或许是因为我对 gradle 不熟悉吧,搜了很多资料才知道可以手动添加 link 依赖,写法如下:

macosX64("macos") {
    binaries {
        executable {
            linkerOpts "-L/usr/lib -liconv"
            entryPoint 'main'
        }
    }
}

这样就可以成功的链接到 iconv 了。在这里多提一句,不要用 brew 安装出来的 iconv,这里面的导出函数名称不对,是故意与系统自带的进行区分的,如果你用了那个库,依然会发现链接失败。


好了,使用 Ktor-Client 的所有问题都解决了,现在可以写点代码来看看成果,我们尝试用 Ktor-Client 来发起请求,并对返回的 json 字符串作出解析。

先用 ktor 实现一个简单的服务端程序,如果你还不会 ktor,可以参考我写的《Ktor 从入门到放弃》系列。

fun Routing.sampletRouting() {
    get("/hello") {
        call.respondText{ "{\"result\": \"callback from server\", \"uuid\":\"${localSession.uuid}\"}" }
    }
}

跑起服务器后,用浏览器访问 http://0.0.0.0/hello 进行验证:

{"result": "callback from server", "uuid":"fba4a6c8-8802-4ff2-b883-78e85a695110"}

然后写一个简单的请求就好了,需要注意的是,Ktor-Client 是运行在协程内的,所以我们同样需要用协程来调用它:

import io.ktor.client.HttpClient
import io.ktor.client.request.get
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.*
import kotlinx.serialization.json.Json

@Serializable
data class Data(val result: String, val uuid: String)

fun main(args: Array<String>) = runBlocking {
    val client = HttpClient()
    val ret = client.get<String>("http://0.0.0.0/hello") { }
    val obj = Json.parse(Data.serializer(), ret)
    println(obj)
}

相关文章

网友评论

    本文标题:[Kotlin/Native] 踩坑,在K/N里使用 Ktor-

    本文链接:https://www.haomeiwen.com/subject/ytqttctx.html