https://kotlinlang.org logo
Title
u

Uli Niggemann

03/22/2023, 8:25 PM
Hello, I am biting my teeth with a CI integration of my kmp project. The project itself is a kmp-project with a native ios and a native android dependency and two kmp modules. All modules are included via submodules and linked into the ios-app via cocoapods. The project itself runs like charm from both xcode and android-studio. I have also a fastlane which builds the ios app via gym - which also works… …on the second launch. The first one always fails with a “framework not found” failure. It looks like some kind of race-condition to me. We faced that issue before in an other kmp-project - the workaround there has been to push the build framework in the build-folder into the git-repo, but I try to avoid it this time. How can I ensure that the framework is created? I tried
gradle(task: "clean assembleDebug")
but that doesn’t do the trick… Thanks for a hint!
j

Javier

03/22/2023, 9:42 PM
you shouldn’t run clean and you should run the ios task, assembleDebug is an android task
u

Uli Niggemann

03/23/2023, 9:25 AM
I didn’t do it in the first place - I added it during the troubleshooting… The framework is created during the build - but the trouble is, that the build fails if the framework is not there… So it only completes in the 2nd try. But I have got a workaround:
kmpModules = ["kmp1", "kmp2"]
kmpModules.each_with_index {|val, index|
    gradle(task: ":#{val}:linkPodReleaseFrameworkIosArm64")
    sh(command: "mkdir -p ../#{val}/build/cocoapods/framework")
    sh(command: "cp -r ../#{val}/build/bin/iosArm64/podReleaseFramework/* ../#{val}/build/cocoapods/framework")
}
The scripts runs ‘linkPodReleaseFrameworkIosArm64’ for every module and copies it to ‘{kmp_module_name}/build/cocoapods/framework’ Afterwards the xCode build is able to build…
l

Landry Norris

03/23/2023, 2:16 PM
If using cocoapods, I’ve seen the same. I have a CI step that runs
./gradlew :module-name:syncFramework -Pkotlin.native.cocoapods.platform=iphonesimulator -Pkotlin.native.cocoapods.archs=x86_64 -Pkotlin.native.cocoapods.configuration=Debug
before each build. It seems to work fine. Note that the args don’t have to actually match the arch/sdk you plan to build. It just needs something built.
I think the issue is that XCode wants to compile the Swift first with the current configuration. It sees that the framework isn’t there yet (since this is CI), and somehow asks gradle to create one, but doesn’t specify which arch/sdk yet. Gradle decides to build a dummy framework, but XCode doesn’t see any symbols (since it’s a dummy framework). For some reason, if there’s already a framework there, XCode is happy, and Gradle builds the proper framework later.
That’s just guesses based on what I’ve seen, though.
u

Uli Niggemann

03/23/2023, 2:44 PM
Hi Landry, at least i am not alone 😉 I’ll give your “static” syncFramework a try - sounds cleaner than my solution…
l

Landry Norris

03/23/2023, 2:46 PM
It would be nice if there were some gradle magic to replace the ‘createDummyFramework’ task with a random build. Anything would be better than placeholder.h, but I guess the proper solution is to figure out how to change the compilation order so the framework is built before Swift tries to access it.
u

Uli Niggemann

03/23/2023, 2:47 PM
Yeah, that is exactly the magic task I have been looking for ;-)