1

我正在开发一个 KMM 项目,并且身份验证在 Android 应用程序上运行良好。但是,当我在 httpclient(位于 shared.commonMain 中)中添加Auth功能时,ios 应用程序在运行时失败并显示以下消息

函数没有或继承 @Throws 注释,因此异常不会作为 NSError 从 Kotlin 传播到 Objective-C/Swift。相反,它被认为是意外和未处理的。程序将终止。

这就是我创建httpclient的方式

private val httpclient = HttpClient() {
    engine {
        pipelining = true
        threadsCount = 4
    }
    install(Logging) {
        level = LogLevel.HEADERS
        logger = object : Logger {
            override fun log(message: String) {
                Napier.v(tag = "HTTP Client", message = message)
            }
        }
    }
    install(JsonFeature) {
        val json =  Json { ignoreUnknownKeys = true }
        serializer = KotlinxSerializer(json)
    }
    install(Auth) {
        basic {
            credentials {
                BasicAuthCredentials(username = emailUser, password = passwordUser)
            }
        }
    }
}.also {
    initLogger()
}

这是 Greeting 类的完整代码:

class Greeting {
private var emailUser: String = ""
private var passwordUser: String = ""

private val httpclient = HttpClient() {
    engine {
        pipelining = true
        threadsCount = 4
    }
    install(Logging) {
        level = LogLevel.HEADERS
        logger = object : Logger {
            override fun log(message: String) {
                Napier.v(tag = "HTTP Client", message = message)
            }
        }
    }
    install(JsonFeature) {
        val json =  Json { ignoreUnknownKeys = true }
        serializer = KotlinxSerializer(json)
    }
    install(Auth) {
        basic {
            credentials {
                BasicAuthCredentials(username = emailUser, password = passwordUser)
            }
        }
    }
}.also {
    initLogger()
}

@Throws(Exception::class)
suspend fun getVaccines(): List<Vaccine> {
    return httpclient.get(endpointBase + Vaccine.path)
}

@Throws(Exception::class)
suspend fun loginUser(email: String, password: String): String? {
    emailUser = email
    passwordUser = password
    return httpclient.get(endpointBase + User.path + "/userPage")
}

}

异常完整的堆栈跟踪

    Function doesn't have or inherit @Throws annotation and thus exception isn't propagated from Kotlin to Objective-C/Swift as NSError.
It is considered unexpected and unhandled instead. Program will be terminated.
Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen com.example.vaccinationcertificate_mobileapp.Greeting@3963788
    at 0   iosApp                              0x000000010c1f728f kfun:kotlin.Throwable#<init>(kotlin.String?){} + 95
    at 1   iosApp                              0x000000010c1efbbd kfun:kotlin.Exception#<init>(kotlin.String?){} + 93
    at 2   iosApp                              0x000000010c1efe2d kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 93
    at 3   iosApp                              0x000000010c2272fd kfun:kotlin.native.concurrent.InvalidMutabilityException#<init>(kotlin.String){} + 93
    at 4   iosApp                              0x000000010c228aff ThrowInvalidMutabilityException + 431
    at 5   iosApp                              0x000000010c3db2c0 MutationCheck + 128
    at 6   iosApp                              0x000000010c151165 kfun:com.example.vaccinationcertificate_mobileapp.Greeting#<init>(){} + 437
    at 7   iosApp                              0x000000010c17c9de objc2kotlin.883 + 142
    at 8   iosApp                              0x000000010c150fa3 $sSo14SharedGreetingCABycfcTO + 19
    at 9   iosApp                              0x000000010c14f0af $sSo14SharedGreetingCABycfC + 31
    at 10  iosApp                              0x000000010c150596 $s6iosApp11ContentViewVACycfC + 38 (/Users/oprisvlad2/projects/VaccinationCertificate/VaccinationCertificate-mobileapp/iosApp/iosApp/ContentView.swift:4:0)
    at 11  iosApp                              0x000000010c14ebf3 $s6iosApp6iOSAppV4bodyQrvgAA11ContentViewVyXEfU_ + 35 (/Users/oprisvlad2/projects/VaccinationCertificate/VaccinationCertificate-mobileapp/iosApp/iosApp/iOSApp.swift:7:4)
    at 12  iosApp                              0x000000010c14eda0 $s6iosApp11ContentViewVIgo_ACIegr_TR + 16
    at 13  iosApp                              0x000000010c14edd1 $s6iosApp11ContentViewVIgo_ACIegr_TRTA + 17
    at 14  SwiftUI                             0x00000001173612cf $s7SwiftUI11WindowGroupV7contentACyxGxyXE_tcfC + 63
    at 15  iosApp                              0x000000010c14eac5 $s6iosApp6iOSAppV4bodyQrvg + 181 (/Users/oprisvlad2/projects/VaccinationCertificate/VaccinationCertificate-mobileapp/iosApp/iosApp/iOSApp.swift:6:3)
    at 16  iosApp                              0x000000010c14ef79 $s6iosApp6iOSAppV7SwiftUI0B0AadEP4body4BodyQzvgTW + 9
    at 17  SwiftUI                             0x0000000116dce845 $s7SwiftUI15AppBodyAccessor33_A363922CEBDF47986D9772B903C8737ALLV06updateD02of7changedyx_SbtF0D0QzyXEfU_TA + 22
    at 18  SwiftUI                             0x0000000117357449 $s7SwiftUI12BodyAccessorPAAE03setC0yy0C0QzyXEFAFyXEfU_ + 34
    at 19  SwiftUI                             0x0000000116dce174 $s7SwiftUI15AppBodyAccessor33_A363922CEBDF47986D9772B903C8737ALLV06updateD02of7changedyx_SbtF + 1310
    at 20  SwiftUI                             0x00000001173575ac $s7SwiftUI10StaticBody33_49D2A32E637CD497C6DE29B8E060A506LLV11updateValueyyF + 161
    at 21  SwiftUI                             0x000000011754055c $s14AttributeGraph0A0VyACyxGqd__c5ValueQyd__RszAA12StatefulRuleRd__lufcADSPyqd__GXEfU_ySv_So11AGAttributeatcyXEfU_ySv_AJtcqd__mcfu_ySv_AJtcfu0_TA + 26
    at 22  AttributeGraph                      0x0000000110585e9b _ZN2AG5Graph11UpdateStack6updateEv + 553
    at 23  AttributeGraph                      0x0000000110586491 _ZN2AG5Graph16update_attributeENS_4data3ptrINS_4NodeEEEj + 411
    at 24  AttributeGraph                      0x000000011058c491 _ZN2AG5Graph20input_value_ref_slowENS_4data3ptrINS_4NodeEEENS_11AttributeIDEjPK15AGSwiftMetadataRhl + 299
    at 25  AttributeGraph                      0x00000001105a2889 AGGraphGetValue + 210
    at 26  SwiftUI                             0x00000001173574d5 $s7SwiftUI10StaticBody33_49D2A32E637CD497C6DE29B8E060A506LLV9container9ContainerQzvg + 67
    at 27  SwiftUI                             0x0000000117357599 $s7SwiftUI10StaticBody33_49D2A32E637CD497C6DE29B8E060A506LLV11updateValueyyF + 142
    at 28  SwiftUI                             0x000000011754055c $s14AttributeGraph0A0VyACyxGqd__c5ValueQyd__RszAA12StatefulRuleRd__lufcADSPyqd__GXEfU_ySv_So11AGAttributeatcyXEfU_ySv_AJtcqd__mcfu_ySv_AJtcfu0_TA + 26
    at 29  AttributeGraph                      0x0000000110585e9b _ZN2AG5Graph11UpdateStack6updateEv + 553

确切的解决方案:

  1. 移动emailUserpasswordUser共同的Main.Platform
expect var emailUser: String  
expect var passwordUser: String
  1. androidMain.Platform
actual var emailUser = "" 
actual var passwordUser = ""
  1. iosMain.Platform
actual var emailUser: String = AtomicReference("").value
actual var passwordUser: String = AtomicReference("").value
4

1 回答 1

1

您需要查看kotlin-native 并发可变性是如何工作的

简而言之,您不能var在共享代码中使用任何可以从不同线程访问的代码。您必须用Atomic容器包装这些值。将emailUser和都替换为passwordUser如下内容:

private val emailUser = Atomic("")
private val passwordUser = Atomic("")

你也可以使用委托属性,这样你就不需要.value每次都写

通用代码没有原子声明,所以你必须自己做。实际上,对于 iOS,您可以使用本机原子,而对于 android,只需进行简单的包装即可。

好消息是这不会持续太久,因为 JetBrains 计划在 KMP 发布之前不久改变并发模型。但现在我们不得不处理它。

于 2021-08-04T13:26:24.393 回答