Hi everyone :wave: I'm currently experimenting KMP...
# swift-export
a
Hi everyone πŸ‘‹ I'm currently experimenting KMP with Swift Export and I've been struggling with an issue. Let me explain πŸ™‚ I've setup a small project with the following configuration :
Copy code
β”œβ”€β”€ androidApp/
β”œβ”€β”€ iOSApp/
└── shared/
	|
	β”œβ”€β”€ core/
	|	└── build.gradle.kts
	└── feature/
		|
		β”œβ”€β”€ featureA/
		|	└── build.gradle.kts
		└── featureB/
			└── build.gradle.kts
Each build.gradle file makes the module available for Swift and Android with something like:
Copy code
kotlin {
	android {
		namespace = "..."
		...
	}

	@OptIn(ExperimentalSwiftExportDsl::class)
	swiftExport {
		moduleName = "..."
		flattenPackage = "..."
	}
}
Then I try to compile the iOS project and I get errors such as :
Copy code
Unable to resolve module dependency: 'ExportedKotlinPackages'
Unable to resolve module dependency: 'KotlinRuntimeSupport'
I've managed to reproduce the problem with the official sample, by adding the android directive to any of the module (shared, module-a and module-b). It looks like swiftExport and android can't be declared in the same module. At the end, I managed to fix the problem by creating an umbrella module, which does the swift export for every modules, only letting the android app use directly the other modules. Is it a known issue, or it might be normal? The way to structure a KMP project with Swift Export seems to be different to the Obj-C export. Is using an umbrella module the right solution? Why can't I export a module directly for Android and Swift?
a
Hello there! Thanks for the report πŸ™‚ I was unable to reproduce the problem based on the description provided. Please see the modified version of the sample, where I try to reproduce the problem. Please either tell me what I'm missing, or provide me with a fork/branch that reproduces the problem πŸ™‚
Each build.gradle file makes the module available for Swift
That is not correct. With swift export umbrella module is not gone - the whole world compilation model on the side of kotlin compiler is still there. With swift export project structure on the side of KMM should be the same - an umbrella module defining what and how would be exported.
The way to structure a KMP project with Swift Export seems to be different to the Obj-C export.
Nope, the recommended structure for both of the exports is the same πŸ™‚ kotlinlang.org/docs/multiplatform/multiplatfor…#…
Is using an umbrella module the right solution?
Yes, it is
Why can't I export a module directly for Android and Swift?
You can. Each kotlin klib/project would be exposed to swift and swift would see it as a separate module. Umbrella module on the side of KMP is a project that defines the nuances of what and how should be built, and what and how should be exposed.
a
I don't have the exact same project anymore, as I was pushing the experiment. But I might have an idea of what could be going on. I'm modularising the iOS app, using a modular architecture such as Tuist's TMA. It means that each feature is an xcodeproj. I initially added the same same script to each feature (
./gradlew :sharedKit:embedSwiftExportForXcode
), so I think the problem is that the shared bit is compiled many times instead of one. See the attached example swift-export-tma. I've introduced an umbrella framework in the iOS app, which is only responsible to bridge the shared bit with the iOS app, making the shared code compiled only once, then used by the features requiring it. I'm still looking into how to setup my iOS project properly, because I keep getting these kinds of errors and I don't really get why.
a
``embedSwiftExportForXcode`` should be called only once, from the "host" target πŸ™‚ We do not have documentation on how to integrate KMP with Tuist, sorry, I don't have a quick guide to show to you. But umbrella module is a way to go πŸ™‚
a
Yeah no worries, I understand πŸ™‚ Just a quick question about
``embedSwiftExportForXcode`` should be called only once, from the "host" target
Is it mandatory to call it from the host target? Or it can be called only from an "bridge" framework? For example :
Copy code
β”œβ”€β”€ iOSApp/
    β”œβ”€β”€ iOSApp/           // Host app. Dependency with sharedBridge
    |    └── iOSApp.swift
    β”œβ”€β”€ feature/
    |    β”œβ”€β”€ featureA/    // Dependency with sharedBridge
    |    └── featureB/    // Dependency with sharedBridge
    └── sharedBridge/     // Framework bridge to the KMP shared module => calls embedSwiftExportForXcode
a
IIUC your setup - yes, calling it from shared bridge should be fine πŸ™‚
πŸ‘ 1
πŸ™‡ 1
a
Well, it doesn't seem to be working when running the gradle task from a xcode framework πŸ˜• Something should be missing either with my configuration or inside the gradle task. It seems not able to find
ExportedKotlinPackages
and
KotlinRuntimeSupport
and I can't point the finger on what's missing.
a
Can you please provide a demo project for that? It would grately simplify the debugging πŸ™‚
a
Here is a demo. The iOS project is initialised. You should be able to open the workspace and compile directly. You can try to compile the target "SharedBridge" as it's the one running the gradle task. The host app is importing SharedBridge. I've simplified the dependency graph by commenting some of the shared dependency in order to keep it as simple as possible. Let me know if you have any issue with the sample.
kodee intensifies 1
I just realised I left kotlin version
2.4.20-Beta2
in the sample. I used
2.4.10
most of the time and I got the same error. It's just that I get another error with the Beta version (related to Koin), but if you get there, it means you fixed the issue πŸ˜›
Was it any helpful? πŸ™‚
a
Hello there. Sorry, I got lost in day to day task. I looked at this problem and it's a duplicate of this - youtrack.jetbrains.com/issue/KT-80346 Basically the problem is that you are targeting swift export to a library target inside xcode project and not the application target.