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+.
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)
- Open your project in Xcode and select File › Add Package Dependencies…
- Enter the repository URL in the search field:
https://github.com/dmsyudha/gatiflow-ios
- Choose Up to Next Major Version with
1.0.0as the minimum. - Select the GatiFlow product and add it to your app target.
Package.swift (manual)
Add the dependency to your Package.swift:
.package(url: "https://github.com/dmsyudha/gatiflow-ios", from: "1.0.0")
Then add it to your target:
.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)
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)
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
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
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.
// Customise the timeout via Config
let config = Config.Builder(appToken: "…")
.watchdogTimeoutMs(3_000) // report hangs longer than 3 s
.build()Disable crash reporting
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
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
// Force-send all buffered events immediately GatiFlow.shared.analytics?.flush()
Disable analytics
GatiFlow.shared.analytics?.setEnabled(false)
User Identity
Associate crashes and events with your own user identifiers. Call this after your authentication flow completes.
// Set after sign-in
GatiFlow.shared.setUserId("usr_abc123")
// Clear on sign-out
GatiFlow.shared.setUserId(nil)Advanced Configuration
| Option | Default | Description |
|---|---|---|
| baseUrl | "https://gatiflow.app" | Base URL of your GatiFlow backend |
| maxCrashQueueSize | 50 | Max crashes stored on disk while offline |
| maxEventBatchSize | 20 | Events per batch before auto-flush |
| flushIntervalMs | 30 000 | Periodic flush interval in milliseconds |
| watchdogTimeoutMs | 5 000 | Main-thread hang threshold in milliseconds |
| debugLogging | false | Print SDK debug logs to console |
API Reference
| Method | Description |
|---|---|
| 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.