I think i’ve decided the worst thing about multipl...
# multiplatform
k
I think i’ve decided the worst thing about multiplatform is having to deal with xcode (the rest is great)! 😅 Here’s what i’m trying to achieve: 1. Multiplatform shared code that is exported as an xcframework using
assembleXCFramework
– called
AnymoCore.xcframework
2. This is then added as a framework to an iOS project (an SDK that I’m creating) which itself produces a framework – called
Anymo.framework
3. The final sdk framework is then consumed by apps – currently just a sample/test app So far my sample app seems to be running fine on the simulator but crashes when trying to run on a device…
Copy code
dyld: Library not loaded: @rpath/AnymoCore.framework/AnymoCore
  Referenced from: /private/var/containers/Bundle/Application/A863B34D-6A54-4D8E-A3A1-69BB07344DE5/iosApp.app/iosApp
  Reason: image not found
If i add my xcframework to my test app directly and try to import some code from
AnymoCore
(rather than
Anymo
) then it works so i think i’m just going wrong at step 2 maybe? I suspect it’s some xcode config or flag that i need to set correctly but am running out of ideas and would appreciate any tips 🙏🏾
this is what my shared
build.gradle.kts
looks like by the way:
Copy code
val xcf = XCFramework(libName)

    ios {
        binaries {
            framework {
                baseName = libName
                xcf.add(this)
            }
        }
    }
b
Xcode is shit in general.
3
😂 2
k
XCode does not support nested XCFrameworks (or even nested regular frameworks for that matter). We were able to work around that issue but the solution is quite involved and we had to build the XCFramework ourselves (ditching assembleXCFramework). I can provide details if you need to go down this route. Otherwise I would suggest using Swift Packages/Cocoapods and add AnymoCore as a dependency for Anymo.
b
Nested frameworks works just fine in Xcode. @kavi I'm doing the exact thing you are describing.
I also ran into the same error at first. What I found is that the default Runpath configuration (a.k.a. @rpath) did not include the path to the nested framework. I was able to fix this by simply adding the necessary path to the build settings.
If you aren't sure what to put, generate an .ipa ("Archive"), and look inside and see where your kotlin framework is located. Add that relative path to the @rpath
k
@Brian G i did think it might be that but as far as i can see my runpath search path looks correct. i’ve attached a screenshot of what it’s set to and what the framework product folder looks like in Finder and it seems to match up? unless i’m not understanding what
@executable_path
and
@loader_path
are (which is v likely!)
b
Yeah, none of those paths tell the app to look INSIDE the Anymo.framework itself for more frameworks, you need to add that explicitly.
k
do you mind giving me an example please? or listing what your paths look like as i’m unsure of the syntax. thanks!
k
Note that if you distribute the framework to other developers, they need to set up the paths in their apps as well. This was a deal breaker for us (we wanted a no-setup xcframework for our customers). I would add @loader_path/Frameworks/Anymo.framework/Frameworks as a search path - the goal is for XCode to search within the Anymo.framework package but you might need to experiment with the exact path. The error message usually tells where XCode is looking so you can adjust it accordingly.
k
tried a few different options in the search path but nothing seemed to work still 😞 will probably give swift packages a go (or revert to cocoapods as a last resort). but the ideal scenario that i’m trying to get to is generate an XCFramework for our internal shared KMM code, which is embedded into our iOS SDK, that is then distributed to customers via Swift Package Manager.
k
Yes, that will work as long as you publish both the internal KMM framework and the iOS SDK as a Swift Package
The route we went in the end was to compile the internal framework as a static framework and include it as a static library (instead of a framework) inside the umbrella framework. Needed a few hacks but it completely hides the internal framework and no nested framework shenanigans are necessary.
b
Karel's solution sounds nice, but yeah, as he said, You have to add
@loader_path/Frameworks/Anymo.framework/Frameworks
to the app, and the consumer's would have to do the same. My library is only used internally (by a few dozen apps) so I'm not too concerned with hiding the nesting.
k
ah having the consumer add that line as well would be a deal breaker so i guess we’ll have to go with SPM/Cocoapods adding that to to the search paths didn’t actually work anyway btw 🙃
any ideas as to why it would work on the simulator and not on device if it’s just a search path issue? surely if it can’t find the framework it wouldn’t work on either architecture?
b
I don't know but I had the exact same experience when I was trying it myself.
k
Note that when using the static framework, you do NOT need to fiddle with the search paths as the inner framework gets completely integrated into the outer framework binary. Simulator is quite forgiving with these library issues, similar to OS X. I feel Apple reused some Mac code there. M1 simulator might behave differently.
b
@Karel Petránek I'd love to hear the necessary steps to get the static nested framework solution set up
k
Sorry, I won't be on my Mac until tomorrow, I will write a thorough guide about how to do it when I get back.