NSExceptionKt

repository·master·Indexed 42 days ago

https://github.com/rickclephas/nsexceptionkt

A Kotlin Multiplatform library that improves crash reports on Apple platforms by capturing unhandled Kotlin exceptions and integrating them with Objective-C/Swift crash reporting SDKs. It preserves stacktraces that are typically lost during termination and provides specific integrations for Bugsnag (v6.22.1+) and Firebase Crashlytics (v9.3.0+), including configurable CausedByStrategy options for Crashlytics.

Tokens
2.3K
Snippets
6
Records
9
Agent score
55%

What's inside NSExceptionKt

  1. Improve Kotlin Native crash reports on Apple platforms

    master

    When developing for Apple platforms with Kotlin Native, unhandled Kotlin exceptions (those without a @Throws annotation) cause the program to terminate immediately. This often results in generic EXC_CRASH (SIGABRT) reports in crash reporting tools, which lack the useful Kotlin stacktrace.

    NSExceptionKt solves this by allowing you to log unhandled Kotlin exceptions before the app is terminated, ensuring that the stacktrace and any 'caused by' exceptions are captured in your crash reporting tool (like Crashlytics or Bugsnag).

  2. How NSExceptionKt handles multiple fatal exceptions in Bugsnag

    master

    Bugsnag can store multiple fatal exceptions, which would normally trigger a fatal Kotlin termination. To prevent these redundant terminations from being logged as new fatal errors, NSExceptionKt uses a feature flag mechanism.

    After an unhandled Kotlin exception is logged, NSExceptionKt sets a feature flag. An addOnSendError filter is then used to drop any subsequent errors that contain this specific feature flag, ensuring the crash reporting flow remains clean.

  3. Install NSExceptionKtCrashlytics for Firebase Crashlytics

    master

    To use NSExceptionKt with Firebase Crashlytics, follow these three steps:

    1. Prerequisite: Ensure you have Firebase Crashlytics (v9.3.0 or above) set up in your iOS project.
    2. Kotlin Configuration: Add the nsexception-kt-core dependency to your appleMain source set and export it in your Apple target binaries. It is recommended to use a static framework.
    3. Xcode Configuration: Add the NSExceptionKtCrashlytics dependency via Swift Package Manager (SPM).

    Note: Use the -spm-crashlytics version suffix when adding the dependency via SPM to prevent it from downloading unnecessary additional dependencies.

    After installation, call NSExceptionKt.addReporter during your app's launch sequence (e.g., in didFinishLaunchingWithOptions).

    kotlin {
        iosArm64 { // and/or any other Apple target 
            binaries.framework {
                isStatic = true // it's recommended to use a static framework
                export("com.rickclephas.kmp:nsexception-kt-core:<version>")
            }
        }
        sourceSets {
            appleMain {
                dependencies {
                    api("com.rickclephas.kmp:nsexception-kt-core:<version>")
                }
            }
        }
    }
  4. Integrate NSExceptionKt with Bugsnag in Swift

    master

    After installing the dependencies, you must register the NSExceptionKt reporter with your Bugsnag configuration in your AppDelegate.

    Use NSExceptionKt.addReporter(.bugsnag(config)) before calling Bugsnag.start(with: config). This ensures that Kotlin exceptions are correctly reported through the Bugsnag pipeline.

    import Bugsnag
    import NSExceptionKtBugsnag
    import shared // This is your shared Kotlin module
    
    class AppDelegate: NSObject, UIApplicationDelegate {
        func application(
            _ application: UIApplication,
            didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
        ) -> Bool {
            let config = BugsnagConfiguration.loadConfig()
            NSExceptionKt.addReporter(.bugsnag(config))
            Bugsnag.start(with: config)
            return true
        }
    }
  5. Install NSExceptionKt for Bugsnag

    master

    To use NSExceptionKt with Bugsnag, follow these three steps:

    1. Prerequisite: Ensure you have Bugsnag (v6.22.1 or above) installed in your iOS project.
    2. Kotlin Configuration: Add the nsexception-kt-core dependency to your appleMain source set and export it in your Apple target binaries. It is recommended to use a static framework.
    3. Xcode Configuration: Add the NSExceptionKtBugsnag dependency to your Xcode project via Swift Package Manager.

    Note: Use the -spm-bugsnag version suffix when adding the dependency to prevent SPM from downloading other unnecessary dependencies.

    kotlin {
        iosArm64 { // and/or any other Apple target 
            binaries.framework {
                isStatic = true // it's recommended to use a static framework
                export("com.rickclephas.kmp:nsexception-kt-core:<version>")
            }
        }
        sourceSets {
            appleMain {
                dependencies {
                    api("com.rickclephas.kmp:nsexception-kt-core:<version>")
                }
            }
        }
    }
  6. Install NSExceptionKt

    master

    NSExceptionKt installation depends on which crash reporting SDK you are using. Follow the implementation-specific guides for your chosen provider:

    • Crashlytics: See NSExceptionKtCrashlytics/README.md for setup.
    • Bugsnag: See NSExceptionKtBugsnag/README.md for setup.
  7. Configure crash reporting tools for the NSExceptionKt Sample

    master

    To run the sample application with functional crash reporting, you must provide configuration files for Google Services, Sentry, and Bugsnag.

    1. Google Services: Place your GoogleService-Info.plist at NSExceptionKtSample/GoogleService-Info.plist.
    2. Sentry & Bugsnag: Create a configuration file at NSExceptionKtSample/NSExceptionKtSample.xcconfig and populate it with your specific credentials.
    SENTRY_ORG = YOUR_ORG
    SENTRY_PROJECT = YOUR_PROJECT
    SENTRY_AUTH_TOKEN = YOUR_AUTH_TOKEN
    SENTRY_DSN = YOUR_DSN
    
    BUGSNAG_API_KEY = YOUR_API_KEY
  8. Configure NSExceptionKt reporter in Swift

    master

    To enable crash reporting, import Firebase, NSExceptionKtCrashlytics, and your shared Kotlin module. Call NSExceptionKt.addReporter within your AppDelegate after FirebaseApp.configure().

    import Firebase
    import NSExceptionKtCrashlytics
    import shared // This is your shared Kotlin module
    
    class AppDelegate: NSObject, UIApplicationDelegate {
        func application(
            _ application: UIApplication,
            didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
        ) -> Bool {
            FirebaseApp.configure()
            NSExceptionKt.addReporter(.crashlytics(causedByStrategy: .append))
            return true
        }
    }
  9. Configure CausedByStrategy for Crashlytics

    master

    Because the Firebase Crashlytics iOS SDK does not natively support the concept of 'caused by' exceptions, NSExceptionKt provides three strategies to manage how exception causes are handled when reporting to Crashlytics:

    • .ignore: Causes are ignored; only the main Throwable is logged as a fatal exception.
    • .append: Causes are appended to the main Throwable and logged as a single fatal exception.
    • .logNonFatal: All causes are logged as individual non-fatal exceptions before the main Throwable is logged as a fatal exception.

    Important Limitation: Crashlytics only stores a single fatal exception. Consequently, the final Kotlin termination will not be recorded by Crashlytics.

    public enum CausedByStrategy {
        /// Causes will be ignored, only the main Throwable is logged as a fatal exception.
        case ignore
        /// Causes are appended to the main Throwable and logged as a single fatal exception.
        case append
        /// All causes are logged as non-fatal exceptions before the main Throwable is logged as a fatal exception.
        case logNonFatal
    }