How do you use multiple xcframeworks exposing the ...
# multiplatform
h
How do you use multiple xcframeworks exposing the same types from a dependency and map this type? I want to create a release xcframework used by the ios app and a test xcframework used by the ios tests. Of course the types in the test xcframework should map to the types used by the release xcframework, but at the moment I get different warnings or different error messages depending on the current workarounds I tried.
a
Hi there! Are you trying to use diamond-like shape in your frameworks dependencies? If so, it could be a problem with statically linked libraries. Consider to use dynamic linking or compile all app at once. To find a better solution, more info about you frameworks configuration (maybe, with names) needed. Also would be nice to see couple of warnings/error messages.
h
Yes exactly. https://github.com/hfhbd/testing-coroutines/tree/macosCI The root/main gradle module uses
coroutines-core
as a dependency in commonMain and exports this dependency using
export(...'core')
. I have another gradle module called
testCounter
using
coroutines-core
as a dependency and also exports this dependency (without it, the types (once shaded, once exported) don't match in Swift). Now I want to use both frameworks in my test module of my iOS app. 1. I can't import both xcframework modules in one Swift file, because Swift has no packages so
Flow
is ambiguous. I need a typealias to prevent this error. 2. Even with typecasting, the types are not the same, so I need a cast. And this cast fails during runtime:
Could not cast value of type 'TestCounter_kobjcc0' (0x6000024fdf80) to 'Testing_coroutinesFlow' (0x105a3c1e8).
Another error: I was unable to import two xcframeworks stored in a folder with the same name:
debug
. Don't know, if this is a Kotlin bug or a spm one.
duplicate dependency 'debug'
If you want to checkout the repo, please use the
macosCI
branch and only use the gradle and the spm project, not the Xcode project
a
Dynamic frameworks should help here. So you need to build all libraries having build flag
MACH_O_TYPE = mh_dylib;
,
isStatic = false
in Gradle or
type: .dynamic
in Swift Package Manager. The test target must include all libraries exactly once. Just to warn: the load of dynamic library takes some time, so it isn’t good for production when number of custom dynamic libraries are huge.
h
Hm, but the default value of
isStatic
is
false
. And using
type: .dynamic
for binary target is not allowed in SPM
a
Ah… my bad. I didn’t realise the coroutines-core is a kotlin library. In this case it will be compiled together with your KMM library. All you need is to export its classes to the headers to make them accessible from Swift: https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#export-dependencies-to-binaries
h
I already exported them, but this is the problem: I export the same dependency from kotlin libs compiled as a xcframework but the underlying lib (coroutines-core) is not recognised as the same type, there still different types from different Swift modules
k
Two frameworks will be incompatible at a binary level, even if their dependencies are the “same” from Kotlin.

https://youtu.be/hrRqX7NYg3Q?t=1758

You can have 2 Kotlin-derived frameworks in the same iOS app, but at a binary level, they’re different and trying to pass classes between them won’t work.
If that’s what you’re asking. If you’re asking something different, let me know.
h
Yeah, this is what I mean.
e
Such a shame that this doesn't seem possible. We have a home-grown KMP logging library that we would like to use in three places: in our shared KMP code, in the iOS app, and in the iOS Bluetooth library we have. The two iOS targets consume the logging library through SPM with the help of KMMBridge, which is something we recently have been trying to achieve because we wanted similar-looking logs from the BLE communication as we get from the shared code. Should also point out that the iOS app drives the configuration of the logging library, which it does on app start - so it calls some setup functions from the logging library. However, regardless of how I try to compile and import these three, I either see logs from 1) shared code or 2) iOS/BLE, not both, which I now see is because the logging library in both of these camps are different copies, so fundamentally different, even though they "look the same" in iOS, i.e. when i configure one of them, the other one isn't configured.
I was looking at the Xcode 15 new feature - mergeable libraries, but haven't figured out if this would even solve the problem, but by looking at the docs, I'm not sure it would
k
Mergeable libraries won't help. You can have multiple KMP-derived frameworks in the same app, but as far as Xcode/iOS is concerned, they're entirely separate. Otherwise you'd get things like "symbol multiply defined" errors. KMP Xcode frameworks are their "own world". All the dependencies included. To the Xcode toolchain, two KMP frameworks are totally separate things, so there'd be nothing to "merge". Of course, if I'm wrong about that, I'd be very interested to hear about it. I haven't actually tried mergable libraries. But, I don't see how they would make any difference.
👍 1
908 Views