Kotlin Multiplatform Ktor iOS端POST请求失败排查求助
KMP+Ktor iOS端POST请求报错「类/文件初始化错误」的排查与修复
问题原因
该错误源于iOS端Kotlin Native运行时与JVM的差异,主要集中在序列化配置、Ktor客户端初始化、协程调用方式三个核心环节,Android端JVM对实验性API、可变字段的兼容性更强,因此未触发异常。
核心失误点
- 实验性序列化注解的兼容性问题:使用
@ExperimentalSerializationApi和@ExperimentalStdlibApi,Kotlin Native对实验性API的支持远不如JVM稳定,会触发类初始化失败。 - Ktor客户端序列化插件配置缺失:共享模块的Ktor客户端未针对iOS端配置完整的Json序列化插件,或依赖未同步添加。
- Suspend函数的Swift调用方式错误:手动传递
callback参数,违背了Kotlin suspend函数暴露给Swift的原生调用逻辑,导致协程上下文初始化异常。 - 数据类可变字段的序列化冲突:
DestinationsResponse中使用var修饰字段,Kotlin Native对可变字段的序列化反射处理存在兼容性问题。
修复方案
1. 移除实验性注解,改用稳定序列化API
将数据类的实验性注解移除,同时将var改为val(不可变字段在Kotlin Native序列化中更稳定):
@Serializable data class DestinationsResponse( val ok: Boolean = false, val error: ErrorInfo? = null, val data: List<BusStop>? = emptyList() ) { fun toJson() = Json.encodeToString(this) }
2. 统一配置跨平台Ktor客户端
使用expect/actual为Android和iOS分别配置Ktor引擎,并确保添加兼容的序列化插件:
// 共享模块定义expect函数 expect fun createHttpClient(): HttpClient // Android模块实现 actual fun createHttpClient(): HttpClient = HttpClient(OkHttp) { install(ContentNegotiation) { Json(Json { ignoreUnknownKeys = true // 忽略服务端返回的未知字段 isLenient = true encodeDefaults = true }) } } // iOS模块实现 actual fun createHttpClient(): HttpClient = HttpClient(Darwin) { install(ContentNegotiation) { Json(Json { ignoreUnknownKeys = true isLenient = true encodeDefaults = true }) } }
3. 修正Suspend函数定义与Swift调用方式
简化Kotlin端suspend函数,直接返回结果(而非嵌套callback),Swift端使用自动生成的completionHandler处理返回值:
// 共享模块API方法修改 suspend fun destinations(departure: DeparturePoint): DestinationsResponse { return try { val param = mapOf( "server" to departure.server, "departure" to departure.id, ) val result = createHttpClient().post("$baseUrl/api/v2/routes/destinations") { contentType(ContentType.Application.Json) setBody(param) }.body<DestinationsResponse>() Instance.api.destinations = result.data ?: emptyList() result } catch (e: Exception) { log.e { "~~~ destinations exception: ${e.message}" } DestinationsResponse() } catch (t: Throwable) { log.e { "~~~ destinations throwable: ${t.message}" } DestinationsResponse() } }
// Swift端调用修改 Instance.companion.api.destinations(departure: departurePoint) { response, error in if let validResponse = response { // 处理正常返回结果 } else if let err = error { // 处理错误 } }
4. 验证依赖配置
确保共享模块的build.gradle.kts中添加了完整的跨平台依赖:
val commonMain by getting { dependencies { implementation("io.ktor:ktor-client-core:2.3.10") implementation("io.ktor:ktor-client-content-negotiation:2.3.10") implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.10") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") } } val iosMain by getting { dependencies { implementation("io.ktor:ktor-client-darwin:2.3.10") } } val androidMain by getting { dependencies { implementation("io.ktor:ktor-client-okhttp:2.3.10") } }
内容的提问来源于stack exchange,提问作者Yar Geel
相关产品推荐
相关产品推荐

