Can someone point me in the right direction in reg...
# multiplatform
i
Can someone point me in the right direction in regards to Crashlytics integration. I'm trying to wrap my head around the fact that a crash can occur in 5 different places:
androidApp
,
iosApp
,
commonMain
,
androidMain
and
iosMain
. How/where do you implement Crashlytics to capture crash reports in any scenario? Thanks!
g
Kermit 1.0 has just been released, more than logs, it's also handling crashlytics for KMP.
🙏 1
k
I had planned a follow up blog post on crash reporting. Guess I'll bump that up in the queue.
🙏 1
i
Thanks guys! Would you say Kermit is the best available practice for crash reporting for KMM?
k
Well, as always, it depends. I'll try to do a quick version of what a longer explanation would be...
i
Much appreciated Kevin! Some guy on stackoverflow suggests this: https://stackoverflow.com/a/67186079/1104337 It sounds too simple and I'm not sure it would capture crashes from androidMain, commonMain and iosMain?
k
For the first issue, the different source sets and platforms, when the ide looks at the different folders, common and the various targets are kind of "different", but when the compiler puts them together, it's all just "source". So, when the Kotlin/Native compiler is building the ios framework,
commonMain
and
iosMain
are the only thing it cares about. For Android,
commonMain
and
androidMain
(and I guess
androidApp
) are all that it cares about. It's kind of hard to describe what I mean there, but from the compiler and runtime's perspective,
commonMain
is just more platform-specific Kotlin (that just happens to have nothing platform specific in it).
For Android, you can just add crashlytics as you would normally, and it'll capture crashes as you would expect. Nothing special needed. For breadcrumbs, you need a way to write them out that will also be accessible from
commonMain
. The way we do that (with Kermit) is there's a "common" LogWriter that will write to Android's Crashlytics on Android. You could do that on your own by simply defining an interface and passing in an implementation on start, but that's what the Kermit LogWriter exists to do.
iOS is more complicated...
That stack overflow answer sucks. No offense to whoever wrote it. I'll need to go add an answer once the blog posts is written. Anyway...
You can also just set up Crashlytics on iOS as you normally would, and you'll get crashes. You can also add breadcrumbs as described by way of an interface in common code that will be implemented from Swift/Objc. However...
If a crash happens in Kotlin code, you will get a useless crash. The stack trace only goes to the point where your Swift/Objc code called into Kotlin code, but you get no info on the Kotlin stack trace.
That's the real trick.
We had https://github.com/touchlab/CrashKiOS/ before the Kermit stuff, and we'll be expanding it a bit (will describe in a bit).
i
I see, that's what I was worried about.
So Kermit solves that problem?
k
Read the README for CrashKiOS. On Kermit, I'm getting there...
i
Will do, thank you so much for all this information!
k
Kermit does a pretty good job of simplifying this situation. Better than CrashKiOS on it's own, which requires you write the Swift/Objc implementation. However, when designing that Kermit integration, I was focused on static frameworks, which is the majority of what we build for a number of reasons. Kermit's Crashlytics integration works with static frameworks only. If you aren't using a static framework, you'll need something a bit more complicated.
This isn't a Kermit thing, it's more of an iOS/Framework thing.
i
I'm using CocoaPods for the shared module
k
Basically, firebase says you shouldn't link the Crashlytics framework inside of your dynamic framework: https://github.com/firebase/firebase-ios-sdk/blob/master/docs/firebase_in_libraries.md
You can use cocoapods, but
isStatic
needs to be true
Copy code
cocoapods {
        framework {
            isStatic = true
        }
    }
If it's dynamic, the way to handle it would be to write your own Kermit LogWriter for iOS and pass it in. Not complicated, but we really need to document that.
We reference that in the docs, but we need a better overall explanation https://github.com/touchlab/Kermit/tree/main/kermit-crashlytics#dynamic-frameworks
It would be (somewhat) more clear if we had a gradle plugin and we could fail the build if the framework is dynamic, but short of that, we'll just need better docs 🙂
i
Oh right, yes, I should be able to add that. Thanks again for your time! I'll start exploring Kermit and come back with specific questions if I have any. Just a quick question for verifying the implementation - I was thinking about placing 3 buttons in iOS and Android apps, and they would cause a crash in iosApp, iosMain and commonMain, and then on Android in androidApp, androidMain and commonMain. If I see all the crashes symbolicated in Crashlytics dashboard, I guess that means the implementation is fully working?
k
Yes, although read how the logs come in. When a crash is caught by the Kotlin handler, it sends a "handled exception" with the Kotlin stack, and then the iOS Crashlytics handler sends a hard crash. So, a crash from inside Kotlin turns into 2 reports. It's ugly for that reason, but without forking the Crashlytics client, there's no way to avoid that. We add tracking info, so you can find the Kotlin stack trace, but it's not ideal, obviously. The Android side is just regular Android crashlytics (1 crash report)
i
Gotcha, no big deal, as long as you can get the reports. Thanks!
k
Also, if you're not used to Crashlytics and Xcode, if you're running the app from Xcode and try to "crash" it, Xcode will catch the crash rather than Crashlytics. Just FYI.
i
Yep, it's gotta be a detached app run without Xcode
👍 1
c
👍
i
Hi @kpgalligan! Any ideas what might be causing these warnings when Xcode is generating the
.app.dSYM
?
Copy code
warning: (x86_64)  could not find object file symbol for symbol _kfun:co.touchlab.crashkios#transformException(kotlin.Throwable;kotlin.Function3<kotlin.String,kotlin.String,kotlin.collections.List<kotlin.Long>,kotlin.Unit>){}
warning: (x86_64)  could not find object file symbol for symbol _kfun:co.touchlab.crashkios.transformException$throwableBoilerplate#internal
warning: (x86_64)  could not find object file symbol for symbol __Konan_init_co.touchlab:crashkios-core
warning: (x86_64)  could not find object file symbol for symbol GCC_except_table0
warning: (x86_64)  could not find object file symbol for symbol GCC_except_table1
warning: (x86_64)  could not find object file symbol for symbol ___unnamed_1
warning: (x86_64)  could not find object file symbol for symbol ___unnamed_2
warning: (x86_64)  could not find object file symbol for symbol ___unnamed_3
warning: (x86_64)  could not find object file symbol for symbol ___unnamed_4
warning: (x86_64)  could not find object file symbol for symbol ___unnamed_5
warning: (x86_64)  could not find object file symbol for symbol ___unnamed_6
Otherwise, everything works great, I'm getting crash reports just like you'd explained it would be
k
I have no idea. What versions of Kotlin and crashkios (or Kermit I guess?) I'm in the process of pushing new everything, and that long promised blog post is in mid-write...
i
Kotlin is 1.6.0 and Kermit 1.0.0