Hi! :wave: We’re starting to share Kotlin code acr...
# kotlin-native
p
Hi! 👋 We’re starting to share Kotlin code across our Android and iOS apps using Objective-C interop with SKIE, and I’d love to hear how other teams preserve a fast, reliable SwiftUI preview workflow. Our iOS developers are concerned that KMP dependencies in UI modules could slow down previews or make them unstable. They’re considering introducing Swift-only interfaces and models with separate implementations for everything exposed to the the UI layers: • A production implementation backed by KMP. • A Swift-only fake implementation for previews, so the previewed UI target wouldn’t link any Kotlin code. The goal is to isolate previews from the Kotlin build and runtime entirely, rather than just avoid executing shared logic. For teams using KMP with SwiftUI, has this separation been worth the extra interfaces and mapping code? Or have direct KMP dependencies worked well enough for previews as your project has grown? If you’ve encountered slow or unreliable previews, what caused the problems, and what helped? We’re aiming for a stable shared API, so API churn isn’t the main concern. We expect to share substantially more logic over time and want to find a pragmatic boundary without maintaining a parallel Swift representation of everything. Concrete experiences, examples, or recommendations would be really appreciated!
p
Ideally when you rebuild your xcode project with no kotlin changes it should be pretty quick (single digit seconds) even for a large kmp library. Most of the time when you're in a preview workflow you're editing swift not kotlin so it ends up being fine. The only gotcha we ran into is that we had to use dynamic linking. I'm not sure why but previews didn't like static linking.
p
Thanks for your input! Yes, we have also enabled dynamic linking because static broke previews (and there were some issues related to tests). I'm not an iOS dev but in my mind the Preview issue is when it's first loaded. But maybe the preview simulator instance (or whatever it is) is only loaded once and is quick for subsequent reloads of the preview? Maybe I should try it out more myself as well, but I'm more concerned that performance could impact DX as the KMP library grows larger. Today our KMP XCFramework (umbrella) is around 40MB but it grows steadily in size and we have barely started.
f
A lot a thing to know, • keep your umbrella under control. • You can share your kotlin mocked data for preview but dynamic linking is required. • Be careful that the default argument is not working for iOS and you need to extend in swift your data if you need default constructor.
• Preview SwiftUI/Compose could use KMP Viewmodel as input but you can have some issues on iOS, I don't advise to use them. Mocked dataclass are fine
The preview and the app share the same kmp library since few xcode versions, so the performance are fine
p
Thanks François. Can you elaborate on what you mean with "keep your umbrella under control"? Do you mean that we shouldn't share too much because of app size concerns? You said that we can share Kotlin mocked data but that means that the entire Umbrella will be pulled in. This is my question. Will that degrade the developer experience for iOS when using previews or is the performance impact negligible? You also say that now the preview and the app share the same kmp library. What was it before? Is there anywhere I can read more about it? Would you be able to tell me approx how large your XCFramework is that you use with previews? My colleagues have a practice that they don't expose any external dependencies (for example Firebase) in their UI modules because they don't want to degrade performance. Are you saying that this is not a concern any more and they don't have to be as careful anymore? We won't be sharing viewmodels but only use cases btw so that they have full control over their UI layer. Let me know if you have any resources that I can learn more about Swift previews and performance (especially if there have been performance improvements in later Xcode versions) 🙏
f
> Can you elaborate on what you mean with “keep your umbrella under control”? Do you mean that we shouldn’t share too much because of app size concerns? The umbrella should contain only necessary content for the iOS application (or not too much), for example, ktor declaration shouldn’t be inside the umbrella. The bigger the umbrella is; the bigger and longer the build time of the binary is; we can see the difference in release build, your CI/CD will thank you. This is something that must be taken care as soon as possible. Tips: use a dedicated Kotlin module that is accessible only from iOS (not the one shared with Android maybe) or use internal/private code visibility to avoid the code to be exported to iOS. > You said that we can share Kotlin mocked data but that means that the entire Umbrella will be pulled in. This is my question. Will that degrade the developer experience for iOS when using previews or is the performance impact negligible? Not necessarily, on my first point, if your mocked class contains simple data type, it’s not an issue. > You also say that now the preview and the app share the same kmp library. What was it before? Is there anywhere I can read more about it? Would you be able to tell me approx how large your XCFramework is that you use with previews? youtrack.jetbrains.com/projects/…/KT-70158/KMP-SwiftUI-Preview-not-working-with-Xcode-16-beta > My colleagues have a practice that they don’t expose any external dependencies (for example Firebase) in their UI modules because they don’t want to degrade performance. Are you saying that this is not a concern any more and they don’t have to be as careful anymore? It’s not a concern I guess, it should not be used in your preview, or I didn’t understand your question well ? > Let me know if you have any resources that I can learn more about Swift previews and performance (especially if there have been performance improvements in later Xcode versions) I don’t have any resource to share, only my experience, I had the same kind of project as yours, and as an iOS developer, I’m taking care of the dev experience. Tips: You can take the power of Gradle by conditioning your build, for example, if your build is in Debug (from env vars), implement a dedicated module for mocked data (or else), you have the flexibility of Gradle with KMP.
Using SKIE or the new Swift Export (if working for you) is a mandatory tool for your iOS developers
p
Thank you François. I assume you mean that we shouldn't expose too much from the API surface? We use Ktor in our shared network layer. You mean that we shouldn't expose any Ktor types at the API surface? Thanks for the reminder about CI/CD. I'll make it a priority to deal with 👍 You said that we should expose mocked classes. I guess we could, but the issue would be if iOS used only one mocked type in their previews the entire Umbrella Framework would get pulled into the preview which could impact preview DX. But we'll test how it actually impacts previews. What I meant with the Firebase example is that if you use a single construct from a framework you pull in the entire framework. So even if you use a simple data class from the KMP library the entire framework will still be pulled into the preview. Your idea of sharing a separate framework with only mocks/protocols could also be a viable option. Then this would be as lightweight as possible and not a performance concern. It'd still export the kotlin runtime but that's probably okay... We already use SKIE but thanks for the reminder! Thank you for taking your time to help me, it's highly appreciated!
f
> We use Ktor in our shared network layer. You mean that we shouldn’t expose any Ktor types at the API surface? Ktor is a Kotlin API; exposing a single property of the API will make all transitive Ktor API exposed for nothing, same thing for datetime,... > simple data class from the KMP library the entire framework will still be pulled into the preview. Yeah, it’s exposed transitively, use a wrapper instead. Tips: • Use specific annotation if you want more control about exposition kotlinlang.org/docs/native-objc-interop.html#… • Avoid
data class
for mock; it’s kind of useless for iOS.
p
Cool, thanks! We do expose one ktor type in one place so I'll try to hide that from the API... Good tip!
f
Thanks, Anytime! Just think your KMP modules as a library you want to share and not just a part of your application, it’s a really different approach.
⭐ 1
🙌 1