Browse docs

Explore by section, then jump directly into a page.

iOS SDK

Swift / iOS SDK

Native iOS analytics — SwiftUI and UIKit screen tracking, deep links, crash capture, push notifications, and A/B experiments.

The Swift SDK uses FlashAnalytics.configureShared() at app launch and provides FlashAnalytics.shared as the global instance. It supports both SwiftUI (via view modifiers) and UIKit (via automatic swizzling).

Prerequisites

Min targetiOS 15.0 / macOS 12.0
Package URLhttps://github.com/NextGenCreativeSolutions/flashanalytics-swift.git
Versionfrom: "1.1.1"

Installation

1

Add the Swift Package

In Xcode: File → Add Package Dependencies and paste the repository URL. Or add to your Package.swift:

Package.swiftSwift
.package(
    url: "https://github.com/NextGenCreativeSolutions/flashanalytics-swift.git",
    from: "1.1.1"
)
2

Initialize in your App entry point

MyApp.swiftSwift
import SwiftUI
import FlashAnalytics

@main
struct MyApp: App {
    init() {
        _ = FlashAnalytics.configureShared(
            options: FlashAnalyticsOptions(
                appId: "YOUR_APP_ID", // UUID from your Flash dashboard
                captureAppLifecycle: true,
                captureScreenViews: true,
                captureDeepLinks: true,
                captureInstallAttribution: true,
                captureNativeCrashes: true,
                captureVariants: CaptureVariantsOptions(),
                batchEnable: true,
                batchSize: 10,
                batchTimeoutMs: 5_000
            )
        )
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}
Store your appId in a configuration file or environment variable. Never hardcode secrets in source code.
3

Identify users and track events

Swift
let analytics = FlashAnalytics.shared

// After login
analytics.identify(
    IdentifyPayload(
        profileId: "user_123",
        email: "user@example.com"
    )
)

// Track a product event
analytics.track("subscription_started", properties: [
    "plan": "pro",
    "price": 49.99
])

SwiftUI screen tracking

Add the .flashAnalyticsScreen modifier to any SwiftUI view to track screen views automatically.

Swift
import FlashAnalytics

struct ProductView: View {
    let productId: String

    var body: some View {
        ProductDetails(productId: productId)
            .flashAnalyticsScreen(FlashAnalytics.shared, path: "/product/(productId)")
    }
}

Auto-capture flags

captureAppLifecycle

app_opened, app_foregrounded, app_backgrounded

captureScreenViews

UIKit screens auto-swizzled, SwiftUI via modifier

captureDeepLinks

deep_link_opened via handleOpenURL / handleUserActivity

captureInstallAttribution

Install / update attribution

captureNativeCrashes

native_crash report on next launch

captureViewInteractions

UIKit control interaction tracking

capturePushLifecycle

Push notification lifecycle helpers

captureVariants

A/B experiment auto-assignment

Deep links

Swift
@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    FlashAnalytics.shared.handleOpenURL(url)
                }
                .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in
                    FlashAnalytics.shared.handleUserActivity(activity)
                }
        }
    }
}

Error tracking

Swift
do {
    try riskyOperation()
} catch {
    analytics.trackError(
        error,
        eventName: "payment_failed",
        properties: ["orderId": orderId]
    )
}

// Track a string error
analytics.trackError("Unexpected nil in user profile")

Experiments

Swift
// All cached assignments — no API call
let all = analytics.getAllExperiments()

// Cache first, API fallback (async)
let assignment = await analytics.getExperimentById(experimentId: "checkout-cta")
print(assignment?.variantName ?? "nil")

// Manual refresh
let assignments = await analytics.autoAssignExperiments()

Global properties

Swift
analytics.setGlobalProperties([
    "appVersion": "1.2.0",
    "plan": "pro",
])

Push notifications

Push tracking is split across two native targets. The table below shows what each event requires:

EventWhereRequires
notification_deliveredService ExtensionUNNotificationServiceExtension + mutable-content: 1
notification_expiredService ExtensionUNNotificationServiceExtension timeout callback
notification_openedApp targetUNUserNotificationCenterDelegate
notification_dismissedApp targetUNUserNotificationCenterDelegate
notification_action_clickedApp targetUNUserNotificationCenterDelegate + category actions

Step 1 — Push payload

Your push payload must include mutable-content: 1 so iOS invokes the service extension before delivery.

Push payload (APNs)JSON
{
  "aps": {
    "alert": { "title": "Your order shipped!", "body": "Tap to track." },
    "mutable-content": 1
  },
  "notificationId": "notif_abc123",
  "messageId": "msg_xyz",
  "provider": "apns"
}

Step 2 — Notification Service Extension (delivery + expiry)

In Xcode: File → New → Target → Notification Service Extension. Add the Flash Analytics package to the extension target, then implement:

NotificationService.swift (Extension target)Swift
import UserNotifications
import FlashAnalytics

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    var extensionAnalytics: FlashAnalytics?

    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        self.contentHandler = contentHandler
        bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent

        // Initialize a dedicated instance for the extension — it runs in a
        // separate process from the app target and cannot share the shared instance.
        extensionAnalytics = FlashAnalytics.configureShared(
            options: FlashAnalyticsOptions(
                appId: "YOUR_APP_ID",
                endpoint: "https://api.flashanalytics.app",
                capturePushLifecycle: true
            )
        )

        // Track delivery — fires notification_delivered
        extensionAnalytics?.trackNotificationDelivered(request: request)

        contentHandler(bestAttemptContent ?? request.content)
    }

    override func serviceExtensionTimeWillExpire() {
        // Fires notification_expired when the extension's processing time runs out
        if let request = bestAttemptContent {
            extensionAnalytics?.trackNotificationExpired(content: request)
        }
        contentHandler?(bestAttemptContent ?? UNNotificationContent())
    }
}

Step 3 — UNUserNotificationCenterDelegate (open + dismiss + action)

In your app target, set the delegate and forward responses to the SDK. With SwiftUI use @UIApplicationDelegateAdaptor.

AppDelegate.swift (App target)Swift
import UIKit
import UserNotifications
import FlashAnalytics

class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        UNUserNotificationCenter.current().delegate = self

        // Request permission
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in }
        application.registerForRemoteNotifications()
        return true
    }

    // Fires notification_opened, notification_dismissed, or notification_action_clicked
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        FlashAnalytics.shared.trackNotificationResponse(response)
        completionHandler()
    }

    // Controls how notifications appear when the app is in the foreground
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        completionHandler([.banner, .sound, .badge])
    }
}
MyApp.swift (SwiftUI entry point)Swift
import SwiftUI

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate

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

Manual batch flush

Swift
// Flush before app background if needed
Task {
    await FlashAnalytics.shared.flushBatch()
}