iOS & macOS
Native Swift SDK for iOS and macOS - signal + NSException crash capture with Mach-O image tracking for dSYM symbolication, app-hang detection, sessions, breadcrumbs and logs.
Requirementslink
- iOS 14+ (CocoaPods or Swift PM) · macOS 11+ (Swift PM) · Swift 5.9 / Xcode 15+
- Depends only on system frameworks (Foundation, Combine, Network) + CryptoKit/swift-crypto
1 - Installlink
Swift Package Manager:
.package(url: "https://github.com/New-Instance-Org/bug-watch-ios.git", from: "0.1.0")CocoaPods:
pod 'BugWatch', '~> 0.1'2 - Initialise (as early as possible)link
import BugWatch
@main
struct MyApp: App {
init() {
BugWatch.start(options: BugWatchOptions(
projectId: Secrets.bugwatchProjectId,
appSecret: Secrets.bugwatchAppSecret,
environment: "production",
release: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0"
))
}
var body: some Scene { WindowGroup { ContentView() } }
}Inject the credentials via an .xcconfig/build setting - keep them out of source control.
3 - Configuration optionslink
| Option | Default | What it does |
|---|---|---|
environment / release | production / - | Labels; release must match dSYM uploads' metadata |
sampleRate | 1.0 | Client-side sampling |
autoSessionTracking | true | Release-health sessions |
enableAppHangTracking / appHangThresholdMs | true / 2000 | Main-thread hang detector |
enableAutoBreadcrumbs | true | Lifecycle breadcrumbs |
enableNetworkBreadcrumbs + allow/deny hosts | true | URLSession breadcrumbs (BugWatch's own ingest calls are excluded) |
sensitiveFields | built-in list | Extra redaction keys |
batchSize / flushIntervalMs / maxQueueSize | 50 / 5000 / 1000 | Delivery + offline queue (persisted in Application Support) |
4 - Capture APIlink
BugWatch.capture(error)
BugWatch.captureMessage("Sync finished", level: .info)
BugWatch.setUser(User(id: "u_123", email: "ada@example.com"))
BugWatch.setTag("tenant", value: "acme")
BugWatch.setContext("payment", value: ["provider": "paystack"])
BugWatch.addBreadcrumb("Tapped checkout")
BugWatch.flush()Automatic capturelink
- Crashes - POSIX signal handlers +
NSSetUncaughtExceptionHandler, recorded with the process's Mach-O binary images (UUID + load address per frame) so the backend symbolicates against your dSYMs. The crash report ships on next launch. - App hangs - main-thread stalls beyond the threshold become events with the hanging stack.
- Delivery is network-aware (NWPathMonitor): offline events wait; nothing is dropped until the queue cap.
5 - Symbolication (CI, macOS runner)link
npx @newinstance/bugwatch-cli symbols upload MyApp.xcarchive \
--release "$MARKETING_VERSION" --build-number "$BUILD_NUMBER" \
--distribution app-store --token "$BUGWATCH_CI_KEY"Accepts .xcarchive, .dSYM bundles, zips of dSYMs, or raw Mach-O files; requires zip on PATH. Matching is by debug UUID, so bitcode-recompiled or multi-machine builds all resolve. Poll Source Maps & Symbols → Get upload status until DONE, then Reprocess any crashes that arrived early.
Troubleshootinglink
- Crash reports missing → crashes upload on the next launch; force-quit during upload delays to the launch after. Check the device clock (>60 s skew rejects tokens).
- Frames show addresses, not symbols → dSYM for that exact build UUID not indexed;
DONEstatus yet? App-store builds need the archive's dSYMs (not the simulator build's). - TestFlight vs App Store confusion → pass
--distributionso the dashboard separates them.
The request below is the exact wire call the SDK makes, including payloadVersion: 2 with binaryImages + nativeStacktrace.