-
Notifications
You must be signed in to change notification settings - Fork 12
Crashlytics Integration
PerformanceSuite/Crashlytics is an additional library that reports fatal and non-fatal hangs to Firebase Crashlytics with their stack traces. Hangs then show up as Crashlytics issues right next to your crashes, with symbolicated stack traces — all threads for fatal issues, the main thread for non-fatal ones — so you can triage them with the same tooling. It depends on PerformanceSuite and on FirebaseCrashlytics.
See also: Hangs.
Add PerformanceSuiteCrashlytics as a target dependency alongside PerformanceSuite. The package URL is the same one you already use:
https://github.com/bookingcom/perfsuite-ios
pod 'PerformanceSuite/Crashlytics'
The Crashlytics subspec depends on FirebaseCrashlytics.
Instead of PerformanceMonitoring.enable(...), call enableWithCrashlyticsSupport(...). Compared to enable, it additionally:
- reads
didCrashPreviouslyfrom Crashlytics for you (Crashlytics.crashlytics().didCrashDuringPreviousExecution()); - wraps the
HangsReceiveryou pass via.hangs(...)so every hang is also reported to Crashlytics — your own receiver still gets the callbacks unchanged.
Make sure FirebaseApp.configure() has been called before this method — the app will crash otherwise.
import PerformanceSuite
import PerformanceSuiteCrashlytics
FirebaseApp.configure()
let metricsConsumer = MetricsConsumer()
let config: Config = [
.hangs(metricsConsumer),
// ... any other config items
]
try PerformanceMonitoring.enableWithCrashlyticsSupport(
config: config,
settings: CrashlyticsHangsSettings()
)The wrapper tracks the lifecycle of a hang so the Crashlytics issue ends up with the correct fatality:
- When a hang starts, an on-demand report is recorded immediately as a fatal hang. If the app is then terminated while still hung (a fatal hang), that report survives and is delivered on the next launch.
- If the hang instead recovers (a non-fatal hang), the wrapper rewrites the pending report as a non-fatal issue and sends it right away.
In both cases the report carries the hang's stack trace (and, for fatal hangs in .fatalHangsAsCrashes mode, a snapshot of all threads), and the Firebase "previously-crashed" marker is cleared so a recovered hang doesn't surface as a phantom crash via didCrashDuringPreviousExecution() on the next launch.
let settings = CrashlyticsHangsSettings(
reportingMode: .fatalHangsAsCrashes, // default
hangReason: "hang", // default issue "reason"
hangTypeFormatter: defaultHangTypeFormatter
)-
reportingMode— how fatal hangs are reported to Crashlytics:-
.fatalHangsAsCrashes(default) — fatal hangs are recorded with Firebase's native crash error type, so the report contains stack traces for all threads (just like a real crash). -
.fatalHangsAsNonFatals— fatal hangs are recorded as non-fatal issues (single-thread stack trace), keeping your crash-free-users metric unaffected by hangs.
-
-
hangReason— the string used as the Crashlytics issue "reason" for every hang. -
hangTypeFormatter— builds the issue name from the hang's fatality and whether it happened during startup. The default produces names likeios_fatal_hang,ios_non_fatal_hang,ios_startup_fatal_hang, andios_startup_non_fatal_hang.
crashlyticsEnabledInDebug (default true) lets you skip all Crashlytics reporting in DEBUG builds. When disabled, enableWithCrashlyticsSupport falls back to a plain enable (no Crashlytics calls, no wrapped receiver), so it is safe to call even when Firebase isn't configured:
try PerformanceMonitoring.enableWithCrashlyticsSupport(
config: config,
settings: CrashlyticsHangsSettings(),
crashlyticsEnabledInDebug: false
)enableWithCrashlyticsSupport also forwards storage, experiments, and sessionIdProvider to enable(...) — see the Usage section in the README and Hangs and previous-session correlation for their semantics.