Closed LivPNavusoft closed 1 month ago
Hmm, that's quite interesting. The KMP-NativeCoroutines annotations should actually completely hide the original declaration from Swift (even if the plugin itself isn't fully configured).
Could you share some more information about your project setup? E.g. is it just a single shared module or multiple shared Kotlin modules? How is KMP-NativeCoroutines configured in the module(s)?
Thank you for getting back to me so quickly! I'll answer your questions first, and then I have an update that may help others...and another related odd problem, lol
We have a single shared kotlin module, with ios and android sourceSets. We use SwiftUI and androidx.Navigation/fragments and activities with traditional views. We use Kodein, so the viewmodels extend DIAware so that we can inject repositories and APIs - removing the DIAware and dependency injections don't resolve the issue and DI works as expected in Android, but I thought it may be relevant.
For NativeCoroutines, in our project build.gradle we preload our plugins for performance and use
plugins {
...
alias(libs.plugins.nativeCoroutines).apply(false)
}
In our shared gradle to actually apply the plugin, we have
plugins{
...
alias(libs.plugins.nativeCoroutines)
}
kotlin{
...
sourceSets {
all {
languageSettings.optIn("kotlinx.cinterop.ExperimentalForeignApi")
languageSettings.optIn("kotlin.experimental.ExperimentalObjCName")
}
}
}
In XCode in the podfile, we use
pod 'KMPNativeCoroutinesAsync', '1.0.0-ALPHA-36' # Swift Concurrency implementation
pod 'KMPNativeCoroutinesCombine', '1.0.0-ALPHA-36' # Combine implementation
pod 'KMPNativeCoroutinesRxSwift', '1.0.0-ALPHA-36' # RxSwift implementation
Regarding the original issue, I thought perhaps part of the build wasn't actually running as expected, so I invalidated caches/cleaned the project/rebuilt. This exposed a Moko Resource related issue we weren't seeing previously; I'm unsure if it's a conflict issue as Moko uses ksp as well, or if it's an existing issue that came up during troubleshooting. For anyone else seeing the following error
Reason: Task ':shared:kspKotlinIosSimulatorArm64' uses this output of task ':shared:generateMRiosSimulatorArm64Main' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
The fix is adding the following to the shared build.gradle
project.afterEvaluate {
tasks.named("kspKotlinIosSimulatorArm64") {
dependsOn("generateMRiosSimulatorArm64Main")
}
tasks.named("kspKotlinIosX64") {
dependsOn("generateMRiosX64Main")
}
tasks.named("kspKotlinIosArm64") {
dependsOn("generateMRiosArm64Main")
}
}
This also appeared to fix, or at least change, the original issue. Now the properties are generated in Swift as
@property (readonly) KmpSharedKotlinUnit *(^(^dummyVarFlow)(KmpSharedKotlinUnit *(^)(NSString * _Nullable, KmpSharedKotlinUnit *(^)(void), KmpSharedKotlinUnit *), KmpSharedKotlinUnit *(^)(NSError * _Nullable, KmpSharedKotlinUnit *), KmpSharedKotlinUnit *(^)(NSError *, KmpSharedKotlinUnit *)))(void) __attribute__((swift_name("dummyVarFlow")));
@property NSString * _Nullable dummyVar __attribute__((swift_name("dummyVar")));
While this seems to be an improvement, issues such as https://github.com/rickclephas/KMP-ObservableViewModel/issues/31 seem to indicate that Bindings should be generated instead of the underlying type variables - in this case String?. I'm using both @NativeCoroutinesState for the properties, as well as @StateViewModel for vm. Is this expected, with manual bindings needing to be used instead?
Regarding the original issue, I thought perhaps part of the build wasn't actually running as expected, so I invalidated caches/cleaned the project/rebuilt. This exposed a Moko Resource related issue we weren't seeing previously; I'm unsure if it's a conflict issue as Moko uses ksp as well, or if it's an existing issue that came up during troubleshooting. For anyone else seeing the following error
Reason: Task ':shared:kspKotlinIosSimulatorArm64' uses this output of task ':shared:generateMRiosSimulatorArm64Main' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
That seems to be a known issue with MOKO resources: https://github.com/icerockdev/moko-resources/issues/514.
This also appeared to fix, or at least change, the original issue. Now the properties are generated in Swift as
@property (readonly) KmpSharedKotlinUnit *(^(^dummyVarFlow)(KmpSharedKotlinUnit *(^)(NSString * _Nullable, KmpSharedKotlinUnit *(^)(void), KmpSharedKotlinUnit *), KmpSharedKotlinUnit *(^)(NSError * _Nullable, KmpSharedKotlinUnit *), KmpSharedKotlinUnit *(^)(NSError *, KmpSharedKotlinUnit *)))(void) __attribute__((swift_name("dummyVarFlow"))); @property NSString * _Nullable dummyVar __attribute__((swift_name("dummyVar")));
I guess Xcode was still seeing an older build of the shared Kotlin module. This is indeed the expected output.
While this seems to be an improvement, issues such as rickclephas/KMP-ObservableViewModel#31 seem to indicate that Bindings should be generated instead of the underlying type variables - in this case String?. I'm using both @NativeCoroutinesState for the properties, as well as @StateViewModel for vm. Is this expected, with manual bindings needing to be used instead?
Yeah bindings are supported for MutableStateFlows
:
$viewModel.dummyVar // Binding<String?>
As long as the data type matches the expected type, you shouldn't need to create a binding manually.
I appreciate the follow up! I was originally having an issue with the binding where XCode couldn't find the proper initializer, but that may have been a cached issue as I'm seeing the bindings now. Apologies the issue seems to have been unrelated, but I appreciate your time and assistance!
I've been seeing a bit of an odd issue that I couldn't find being addressed elsewhere. I was able to create viewModels that work as expected in Android, and have @NativeCoroutinesState etc to map them to Swift. However, regardless of the variable's type, it's ported over as an "any".
For example, the following property in my kotlin common code's viewmodel
@NativeCoroutinesState var dummyVar = MutableStateFlow<String?>(viewModelScope, null)
Is generated in Swift as
@property id<KmpSharedKotlinx_coroutines_coreMutableStateFlow> dummyVar __attribute__((swift_name("dummyVar")));
Subsequently, I'm unable to use them in TextFields etc in Swift. This is the case for any type, nullable or otherwise. I was originally having this issue with the viewmodels before adding KMP-NativeCoroutines, but adding the library to Kotlin & Swift and adding the expected annotations doesn't seem to have had an effect.
Apologies if I'm missing something, but I greatly appreciate any assistance! Below is some versioning I thought may be relevant