Hello! Does anyone know if it matters if I add "F...
# touchlab-tools
d
Hello! Does anyone know if it matters if I add "FirebaseAnalytics" to the iOS app as a static or dynamic framework? https://crashkios.touchlab.co/docs/crashlytics/
👀 1
b
How are you adding Firebase analytics to your ios app? As an Swift Package Manager package (File > Add Packages) or some other method?
d
As SPM package
My problem is that I get crashes directly when opening the app (only when running release builds from Apple, such as testflight)
Otherwise stuff works
b
ah!
I had that exact same issue
d
Oh
b
You have two choices
1. Set your shared module to be linked statically 2. Use a different library for getting crash reports to firebase
d
We've had our KMP module static for a while, but the problem is it's (AFAIK) impossible to get SwiftUI Previews working if the KMP module is statically linked. Is bugsnag the alternative then?
Or which route did you go?
b
but the problem is it's (AFAIK) impossible to get SwiftUI Previews working if the KMP module is statically linked.
Correct! You can still use firebase, you just can't use CrashKiOS .. hang on let me find my other thread that talks about this
d
🙏
I feel like https://crashkios.touchlab.co/docs/crashlytics/ should mention this
👍 1
b
I mentioned you in the other thread
d
Saw that! Thanks a lot! Will read up.
b
There is a defect filed in the crashkios github issue tracker https://github.com/touchlab/CrashKiOS/issues/69
👍 1
Also, in that thread, someone posted a link to a blog post. That didn't help me any
Basically, you'll want to use https://github.com/rickclephas/NSExceptionKt instead of CrashKiOS
The good news is, CrashKiOS uses that same library internally, so you aren't really changing much.
d
Ah, ok. This feels really promising!
Thanks for your time!
b
Sure. the NSExceptionKt was easy to implement.
k
Updates on this
(I'm one of the maintainers of CrashKiOS)
My problem is that I get crashes directly when opening the app (only when running release builds from Apple, such as testflight)
This is a known issue. It seems that somewhere in that pipeline, necessary symbols are being stripped. We've iterated on trying to solve it, but it's really deep-native linking stuff, and not easy to deal with. The general problem is that KMP and native 3rd party integration is a huge pain. It has been a serious KMP issue, and will very much impact library dev for CMP. Solving it is not trivial, but this problem really needs a more general solution than the "fixes" each library tries to use.
We've had our KMP module static for a while, but the problem is it's (AFAIK) impossible to get SwiftUI Previews working if the KMP module is statically linked.
This specific problem has a reasonable workaround. Make debug builds dynamic and release builds static. How you do that depends on how you hand off to iOS devs. I took a dive into how NSExceptionKt avoids the linking issue, and assuming I'm correct, nothing in Kotlin directly calls the code generated by cinterop. It's a clever workaround, but that means you can't do things like log breadcrumbs, add data, send handled exceptions (directly), etc. I think. Assuming I'm correct, that won't really work for CrashKiOS, unless we took out all of those features. The current problem specific to Crashlytics is, I believe, the result of a change we made to get around the linking issues. Rather than use cinterop to talk to Crashlytics, we're dynamically calling the Objc methods. That works, unless something in the release pipeline removes something it doesn't think is being used but actually is. That's my current understanding of the situation (I didn't work on that specifically). To update CrashKiOS, we need a refactor that doesn't try to avoid cinterop in the same way, and I want to apply it to both Crashlytics and Bugsnag, because the linking situation is a mess in general. Early versions of CrashKiOS actually required copy/pasting Swift code, which is ugly, but simple. Other options include using CocoaPods to link Crashlytics, but using SPM externally. This is what Sentry does, which works, but generally gets a 🤮 response. I have another clever idea, but I'm kind of tired of clever ideas, so I'm not sure we'll do that one 🙂
Alternatively, if using NSExceptionKt, you could create an interface with the other features and pass in platform-specific implementations. That would work, and is roughly what our original copy/paste solution was, but that kind of defeats the purpose of having a library try to provide that.
d
Hi @kpgalligan Thank you for the long and thorough response! I will try go ahead for now to use different integration methods depending on debug/release builds. For now we've integrated integrated KMP in monorepo style, and always use
./gradlew watch:embedAndSignAppleFrameworkForXcode
I guess your suggestion the is to use XCFramework for releases and
embedAndSignAppleFrameworkForXcode
for debug?
k
Hmm. I haven't tried that kind of thing with
embedAndSignAppleFrameworkForXcode
. What the CocoaPods plugin used to do is pass env vars from Xcode to tell Kotlin what architecture and variant to use. I would assume
embedAndSignAppleFrameworkForXcode
does something similar, or it would just build "everything" every time, and that's clearly not how it works. I would maybe try adding code to Gradle to print out all env vars, then do a debug build and a release build. Then you could flip static/dynamic based on that.
Or dig into the Kotlin Gradle plugin code directly, but that sounds terrible.
d
Hm, yeah, we'll. We did the cocoapods integration before, but that is just so slow when developing features in KMP + iOS simultaneously
k
Oh, I wouldn't suggest going back to CocoaPods. I very much prefer
embedAndSignAppleFrameworkForXcode
. I'm just guessing it also uses env vars in some way to communicate to the Kotlin compiler, so you could maybe use those to flip the static flag.
d
Yeah, it does, you can't build
embedAndSignAppleFrameworkForXcode
from the terminal for example, due to just that!
But I guess I could invoke different gradle tasks from Xcode based on config?
k
Oh, no, I mean in Gradle, write some code that actually gets the env var and flip the static flag in Gradle. So, when Xcode calls Gradle with
embedAndSignAppleFrameworkForXcode
, it's (probably) setting something like
BUILD_VARIANT=DEBUG
as an env var. Once you figure out the name and values, you can just do an
if
in gradle to change the static flag. When you're doing dev, that won't change from build to build, so it shouldn't blow up your config time.
👍 1
so it shouldn't blow up your config time.
Key word is "shouldn't"
d
Think it probably is:
Copy code
KOTLIN_FRAMEWORK_BUILD_TYPE
k
Sounds like it. If you get something working I'd love to see it. Outside of CrashKiOS-related trouble, I generally prefer static libraries, but the SwiftUI preview is a problem, so it's just a good tool to have in the box.
d
Yepp! Will get back once I've played more with it tomorrow.
👍 1
b
@kpgalligan Showing my ios/linking ignorance here ...
Make debug builds dynamic and release builds static.
I considered that approach, but the QA in me worries about that introducing defects that don't get caught early enough in development. I'm sure we've all ran into a similar issue in Android in our lives, where code works fine in debug builds, but release builds crash because Proguard is stripping some class out. Feels like we could run into similar situations in ios if we use a static/dynamic switch?
As soon as the word "linking" gets uttered, my eyes glaze over and confusion sets in 😄
k
Feels like we could run into similar situations in ios if we use a static/dynamic switch?
Well, it's one of those "pick your poison" kind of situations. I can't say you absolutely won't, but I can say there are other things that can (and have) happened. For example, I've had issues simply using release vs debug builds. Forget static vs dynamic. In theory, issues between static and dynamic would be reasonably fatal, which is good because you'd know immediately. Also, assuming you have QA builds, or at least some kind of dogfood builds, those would all be built with release binary, and/or you could force them to use a static build, so it's a risk that could be minimized to virtually zero.
it's a risk that could be minimized to virtually zero.
That is the risk of publishing anything with an issue.
b
That's good to know. Sounds very similar to the ProGuard "issue". Yeah it can happen, but if your development processes are right, it shouldn't (or should be very rare).
k
That's actually a great analogy
Very similar
b
I might put CrashKiOS back in and try that out.
k
I wish you all the native-linker-luck I can. I feel like half of my debug energy right now is linking.
If you run into something, @ me. I go into deep focus mode and only check slack sporadically.
b
yep same. Since you aked, I will say if you get a few minutes, Im still being plagued by this issue with Default Argument Interop with SKIE https://github.com/touchlab/SKIE/issues/111
k
Ooohhh, yeah, SKIE's a bit out of my wheelhouse when you get into the weeds of what it's doing, TBH. I'll bring it up at the next sync meeting, though.
gratitude thank you 1
d
This seems to work. Also verified by checking the resulting .app that it contains the shared
.framework
when building
debug
, but not for
release
.
🎉 1
👀 2
k
Nice. I think we'll add something like this to the CrashKiOS docs. We still need to figure out an update, but this should help until we do.
😊 1