Back to Diagnostics|GatiFlow iOS SDKv1.0.0
RequirementsInstallationInitializationCrash ReportingAnalyticsUser IdentityAdvanced ConfigAPI ReferenceTroubleshooting

iOS SDK

Add crash reporting, ANR/hang detection, and event analytics to your iOS app in minutes. The SDK is built with Swift Package Manager, has zero third-party dependencies, and works with iOS 13+.

iOS 13+Swift 5.9+Xcode 15+Swift Package ManagerURLSession

Requirements

  • iOS 13.0 or later
  • Xcode 15 or later
  • Swift 5.9 or later
  • Swift Package Manager (bundled with Xcode)

Installation

Swift Package Manager (Xcode)

  1. Open your project in Xcode and select File › Add Package Dependencies…
  2. Enter the repository URL in the search field:
text
https://github.com/dmsyudha/gatiflow-ios
  1. Choose Up to Next Major Version with 1.0.0 as the minimum.
  2. Select the GatiFlow product and add it to your app target.

Package.swift (manual)

Add the dependency to your Package.swift:

swift
.package(url: "https://github.com/dmsyudha/gatiflow-ios", from: "1.0.0")

Then add it to your target:

swift
.product(name: "GatiFlow", package: "gatiflow-ios")

Initialization

Initialize the SDK in your AppDelegate or @main struct. Call GatiFlow.shared.start(…) as early as possible so crashes during startup are captured.

UIKit (AppDelegate)

swift
import GatiFlow

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GatiFlow.shared.start(
            appToken: "YOUR_APP_TOKEN",
            services: [Crashes(), Analytics()]
        )
        return true
    }
}

SwiftUI (@main)

swift
import SwiftUI
import GatiFlow

@main
struct MyApp: App {
    init() {
        GatiFlow.shared.start(
            appToken: "YOUR_APP_TOKEN",
            services: [Crashes(), Analytics()]
        )
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

Custom configuration

swift
let config = Config.Builder(appToken: "YOUR_APP_TOKEN")
    .baseUrl("https://gatiflow.app")
    .maxEventBatchSize(20)
    .flushIntervalMs(30_000)
    .watchdogTimeoutMs(5_000)
    .debugLogging(true)   // disable in production
    .build()

GatiFlow.shared.start(config: config, services: [Crashes(), Analytics()])

Crash Reporting

The Crashes service installs an NSUncaughtExceptionHandler and POSIX signal handlers (SIGSEGV, SIGABRT, SIGBUS,SIGILL, SIGFPE, SIGTRAP) so both Objective-C/Swift exceptions and native crashes are captured. Crashes are written to disk before any network call to guarantee delivery.

Handled errors

swift
do {
    try riskyOperation()
} catch {
    GatiFlow.shared.crashes?.trackError(error, metadata: [
        "screen": "PaymentScreen",
        "user_action": "tap_submit",
    ])
}

Hang / watchdog detection

A background watchdog checks whether the main thread responds within watchdogTimeoutMs (default 5 s). If the main thread is blocked, a WatchdogMonitorException is reported automatically.

swift
// Customise the timeout via Config
let config = Config.Builder(appToken: "…")
    .watchdogTimeoutMs(3_000)  // report hangs longer than 3 s
    .build()

Disable crash reporting

swift
GatiFlow.shared.crashes?.setEnabled(false)

Analytics

Track custom events with an optional properties dictionary. Events are batched and flushed automatically at the configured interval or when the batch size is reached.

Track events

swift
GatiFlow.shared.analytics?.trackEvent("screen_view", properties: [
    "screen_name": "HomeScreen",
])

GatiFlow.shared.analytics?.trackEvent("purchase_completed", properties: [
    "product_id": "pro_monthly",
    "price": 9.99,
    "currency": "USD",
])

Manual flush

swift
// Force-send all buffered events immediately
GatiFlow.shared.analytics?.flush()

Disable analytics

swift
GatiFlow.shared.analytics?.setEnabled(false)

User Identity

Associate crashes and events with your own user identifiers. Call this after your authentication flow completes.

swift
// Set after sign-in
GatiFlow.shared.setUserId("usr_abc123")

// Clear on sign-out
GatiFlow.shared.setUserId(nil)

Advanced Configuration

OptionDefaultDescription
baseUrl"https://gatiflow.app"Base URL of your GatiFlow backend
maxCrashQueueSize50Max crashes stored on disk while offline
maxEventBatchSize20Events per batch before auto-flush
flushIntervalMs30 000Periodic flush interval in milliseconds
watchdogTimeoutMs5 000Main-thread hang threshold in milliseconds
debugLoggingfalsePrint SDK debug logs to console

API Reference

MethodDescription
GatiFlow.shared.start(appToken:services:)Initialise the SDK with a token and service list
GatiFlow.shared.start(config:services:)Initialise with a full Config object
GatiFlow.shared.setUserId(_:)Associate events/crashes with a user ID (pass nil to clear)
GatiFlow.shared.stop()Flush remaining events and shut down all services
crashes?.trackError(_:metadata:)Report a handled error with optional metadata
crashes?.setEnabled(_:)Enable or disable crash reporting at runtime
analytics?.trackEvent(_:properties:)Track a named event with optional properties
analytics?.flush()Immediately flush buffered events
analytics?.setEnabled(_:)Enable or disable event tracking at runtime

Troubleshooting

No crashes appearing in the dashboard

Ensure the app token matches your project. Enable debug logging (`.debugLogging(true)`) and check the console for HTTP errors. Crashes are queued on disk and sent on the next app launch if the network is unavailable.

Watchdog fires on legitimate background work

Increase `watchdogTimeoutMs` in your Config, or move the heavy work off the main thread to a `DispatchQueue.global()` queue.

Events are delayed or missing

Call `GatiFlow.shared.analytics?.flush()` before your app enters the background (e.g. in `applicationDidEnterBackground`) to ensure in-flight events are sent.

SDK conflicts with another crash reporter

The GatiFlow `Crashes` service chains to any previously installed `NSUncaughtExceptionHandler`, so both reporters should work. If you see issues, initialise GatiFlow last so it is at the front of the chain.