Skip to content

Crashlytics Integration

Gleb Tarasov edited this page Jun 25, 2026 · 1 revision

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.

Installation

Swift Package Manager

Add PerformanceSuiteCrashlytics as a target dependency alongside PerformanceSuite. The package URL is the same one you already use:

https://github.com/bookingcom/perfsuite-ios

CocoaPods

pod 'PerformanceSuite/Crashlytics'

The Crashlytics subspec depends on FirebaseCrashlytics.

Usage

Instead of PerformanceMonitoring.enable(...), call enableWithCrashlyticsSupport(...). Compared to enable, it additionally:

  • reads didCrashPreviously from Crashlytics for you (Crashlytics.crashlytics().didCrashDuringPreviousExecution());
  • wraps the HangsReceiver you 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()
)

How hangs are reported

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.

Customizing reporting — CrashlyticsHangsSettings

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 like ios_fatal_hang, ios_non_fatal_hang, ios_startup_fatal_hang, and ios_startup_non_fatal_hang.

Disabling Crashlytics in DEBUG

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.

Clone this wiki locally