### Carthage Installation Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Specify SwiftAnalyticsKit in your Cartfile to integrate it into your Xcode project using Carthage. ```ogdl github "SwiftyLab/SwiftAnalyticsKit" ``` -------------------------------- ### CocoaPods XCFramework Installation Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Alternatively, use the pre-built XCFramework from GitHub releases via CocoaPods by specifying the http URL in your Podfile. ```ruby pod 'SwiftAnalyticsKit', :http => 'https://github.com/SwiftyLab/SwiftAnalyticsKit/releases/download/v{version}/SwiftAnalyticsKit-{version}.xcframework.zip' ``` -------------------------------- ### CocoaPods Installation Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Integrate SwiftAnalyticsKit into your Xcode project using CocoaPods by specifying the dependency in your Podfile. The Mock subspec can be added for test targets. ```ruby pod 'SwiftAnalyticsKit' ``` ```ruby pod 'SwiftAnalyticsKit/Mock' ``` -------------------------------- ### Test Event Routing with MultiplexAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Use the expect helper on XCTestCase to create and register XCTestExpectations with AnalyticsExpectationHandlers. This example demonstrates routing events to specific handlers based on event group. ```swift import XCTest import AnalyticsMock import Analytics final class MultiplexTests: XCTestCase { @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) func testMultiplexRouting() throws { let actionHandler = AnalyticsSingleExpectationHandler() let stateHandler = AnalyticsSingleExpectationHandler() var mux = MultiplexAnalyticsHandler() mux.register(handler: actionHandler, for: .action) mux.register(handler: stateHandler, for: .state) // loginScreenViewed is .state — only stateHandler should fire. let noActionExpectation = expect(event: "loginScreenViewed", on: actionHandler) noActionExpectation.isInverted = true // must NOT be fulfilled expect(event: "loginScreenViewed", on: stateHandler) { (event: LoginEvent, data: LoginEvent.Metadata) in XCTAssertEqual(event.group, .state) } LoginEvent.loginScreenViewed.fire(on: mux) waitForExpectations(timeout: 1) } } ``` -------------------------------- ### Implement ThrottleConfiguration for Analytics Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Implement the AnalyticsConfiguration protocol to create custom event processing logic. This example shows a throttle configuration that drops events fired within a specified interval. ```swift import Analytics import Foundation // A throttle configuration that drops events fired within 500 ms of the last. final class ThrottleConfiguration: AnalyticsConfiguration { private var lastFired: Date? private let interval: TimeInterval init(interval: TimeInterval = 0.5) { self.interval = interval } func process( event: Event, at time: Date = .init(), data: Event.Metadata, for handler: Handler ) where Event.Name == Handler.EventName { let now = Date() guard lastFired.map({ now.timeIntervalSince($0) >= interval }) ?? true else { return } lastFired = now handler.track(event: event, at: time, data: data) } } // Attach the configuration to an event type. enum SearchEvent: String, AnalyticsEvent { case queryChanged typealias Metadata = EmptyMetadata var configuration: AnalyticsConfiguration { ThrottleConfiguration(interval: 0.3) } } ``` -------------------------------- ### Implement Custom AnalyticsEncoder with JSONSerialization Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Define a custom AnalyticsEncoder to serialize AnalyticsMetadata into a specific output format. This example uses JSONSerialization to produce a [String: Any] dictionary. ```swift import Analytics import Foundation // Custom encoder producing a [String: Any] dictionary via JSONSerialization. struct MyDictionaryEncoder: AnalyticsEncoder { func encodeMetadata(_ data: T) throws -> [String: Any] { let jsonData = try JSONEncoder().encode(data) guard let dict = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] else { throw EncodingError.invalidValue(data, .init(codingPath: [], debugDescription: "Not a dictionary")) } return dict } } // Use inside a handler: struct FirebaseHandler: AnalyticsHandler { typealias EventName = String let encoder = MyDictionaryEncoder() func track( event: Event, at time: Date, data: Event.Metadata ) where Event.Name == String { guard let params = try? encoder.encodeMetadata(data) else { return } // Analytics.logEvent(event.name, parameters: params) print("Firebase.logEvent(\(event.name), \(params))") } } ``` -------------------------------- ### Initialize Git Repository Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Run this command if your project is not already a Git repository before adding SwiftAnalyticsKit as a submodule. ```bash $ git init ``` -------------------------------- ### Swift Package Manager Binary Target Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Optionally, use the pre-built XCFramework from GitHub releases as a binary target in your Swift package. ```swift .binaryTarget(name: "Analytics", url: "https://github.com/SwiftyLab/SwiftAnalyticsKit/releases/download/v{version}/SwiftAnalyticsKit-{version}.xcframework.zip", checksum: "{checksum}") ``` -------------------------------- ### Add SwiftAnalyticsKit as Git Submodule Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Adds the SwiftAnalyticsKit repository as a submodule to your current project. This command should be run from your project's root directory. ```bash $ git submodule add https://github.com/SwiftyLab/SwiftAnalyticsKit.git ``` -------------------------------- ### Swift Package Manager Dependency Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/README.md Add SwiftAnalyticsKit as a dependency in your Swift package's Package.swift file. Ensure to add the 'Analytics' product to your targets. ```swift .package(url: "https://github.com/SwiftyLab/SwiftAnalyticsKit.git", from: "1.0.0"), ``` ```swift .product(name: "Analytics", package: "SwiftAnalyticsKit") ``` ```swift .product(name: "AnalyticsMock", package: "SwiftAnalyticsKit") // To use mocks, i.e. in test targets ``` -------------------------------- ### Test Checkout Sequence with Ordered Expectations Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Use AnalyticsOrderedExpectationHandler to test sequences of events, ensuring they are fulfilled in the order they are registered. This is useful when the same event can occur multiple times. ```swift import XCTest import AnalyticsMock import Analytics final class CheckoutSequenceTests: XCTestCase { func testCheckoutSequence() { let handler = AnalyticsOrderedExpectationHandler() // First loginAttempted must have user "alice". expect(event: "loginAttempted", on: handler) { (event: LoginEvent, data: LoginEvent.Metadata) in XCTAssertEqual(data.user, "alice") } // Second loginAttempted (retry) must have user "alice" again. expect(event: "loginAttempted", on: handler) { (event: LoginEvent, data: LoginEvent.Metadata) in XCTAssertEqual(data.user, "alice") } // Simulate two login attempts. let ts = Date.now LoginEvent.loginAttempted.fire(on: handler, data: .init(user: "alice", timestamp: ts)) LoginEvent.loginAttempted.fire(on: handler, data: .init(user: "alice", timestamp: ts)) waitForExpectations(timeout: 1) } } ``` -------------------------------- ### Implement ConsoleAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Conform to the AnalyticsHandler protocol to create a custom backend that prints events to the console. This is useful for debugging and testing analytics integrations. ```swift import Analytics import Foundation // A simple console-printing backend. struct ConsoleAnalyticsHandler: AnalyticsHandler { typealias EventName = String func track( event: Event, at time: Date, data: Event.Metadata ) where Event.Name == String { let encoder = StandardDictionaryEncoder() // from AnalyticsMock let params = (try? encoder.encodeMetadata(data)) ?? [:] print("[\(time)] \(event.name) [\(event.group)] — \(params)") } } // Use it directly: let console = ConsoleAnalyticsHandler() LoginEvent.loginSucceeded.fire(on: console, data: .init(user: "alice", timestamp: .now)) // → [2024-01-15 12:00:00] loginSucceeded [action] — ["user": "alice", "timestamp": ...] ``` -------------------------------- ### MultiplexAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Routes events to multiple backends simultaneously based on AnalyticsGroup. Requires Swift 5.7+ / iOS 16+. ```APIDOC ## MultiplexAnalyticsHandler (Swift 5.7+ / iOS 16+) ### Description Routes a single event to multiple backends simultaneously. Each registered handler is associated with one or more `AnalyticsGroup` values; a handler only receives events whose `group` intersects its registered groups. Preserves full generic type information during dispatch. ### Usage ```swift import Analytics @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) func buildHandler() -> MultiplexAnalyticsHandler { var mux = MultiplexAnalyticsHandler() mux.register(handler: amplitudeHandler, for: .action) mux.register(handler: mixpanelHandler, for: [.action, .state]) mux.register(handler: debugLogger, for: .defaultGroups) mux.register(handler: encryptedStore, for: .sensitive) return mux } let mux = buildHandler() LoginEvent.loginScreenViewed.fire(on: mux) // → mixpanelHandler + debugLogger LoginEvent.loginAttempted.fire(on: mux, data: .init(user: "alice", timestamp: .now)) // → amplitudeHandler + mixpanelHandler + debugLogger UserIdData(id: "uid_123").send(to: mux) // → encryptedStore + debugLogger ``` ``` -------------------------------- ### Define and Fire Analytics Events Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Define events using enums conforming to `AnalyticsEvent`. Metadata can be shared or specific to each event case. Use the `fire(on:data:)` method to send events with or without explicit metadata. ```swift import Analytics // Define events as a RawRepresentable enum — `.name` is derived from `.rawValue` automatically. enum LoginEvent: String, AnalyticsEvent { case loginScreenViewed case loginAttempted case loginSucceeded case loginFailed // Metadata is shared across all cases; use EmptyMetadata if none is needed. struct Metadata: AnalyticsMetadata { let user: String let timestamp: Date } // Override group per-case; default is .action. var group: AnalyticsGroup { switch self { case .loginScreenViewed: return .state default: return .action } } } // Fire an event with explicit metadata. let handler = MyAnalyticsHandler() LoginEvent.loginAttempted.fire(on: handler, data: .init(user: "alice", timestamp: .now)) // Fire an event whose metadata is Initializable (has a zero-arg init). LoginEvent.loginScreenViewed.fire(on: handler) ``` -------------------------------- ### Build MultiplexAnalyticsHandler for Multiple Backends Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Implement MultiplexAnalyticsHandler to route a single event to multiple analytics backends simultaneously. Handlers are registered with specific AnalyticsGroup values, ensuring they only receive events whose groups intersect with their registered groups. This requires Swift 5.7+ or iOS 16+. ```swift import Analytics @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) func buildHandler() -> MultiplexAnalyticsHandler { var mux = MultiplexAnalyticsHandler() // Backend A only receives action events. mux.register(handler: amplitudeHandler, for: .action) // Backend B receives both action and state events. mux.register(handler: mixpanelHandler, for: [.action, .state]) // Backend C receives all groups. mux.register(handler: debugLogger, for: .defaultGroups) // Backend D only tracks sensitive (e.g., PII-aware) events. mux.register(handler: encryptedStore, for: .sensitive) return mux } let mux = buildHandler() LoginEvent.loginScreenViewed.fire(on: mux) // → mixpanelHandler + debugLogger LoginEvent.loginAttempted.fire(on: mux, data: .init(user: "alice", timestamp: .now)) // → amplitudeHandler + mixpanelHandler + debugLogger UserIdData(id: "uid_123").send(to: mux) // → encryptedStore + debugLogger ``` -------------------------------- ### Test Analytics Event Tracking with XCTestExpectations Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Employ AnalyticsSingleExpectationHandler from AnalyticsMock to integrate with XCTest for verifying analytics events. It registers an expectation for each event name, fulfilling it when the event fires. ```swift import XCTest import AnalyticsMock import Analytics final class LoginFlowTests: XCTestCase { func testLoginSuccessTracked() { let handler = AnalyticsSingleExpectationHandler() // Register expectation with a validation closure. expect(event: "loginSucceeded", on: handler) { (event: LoginEvent, data: LoginEvent.Metadata) in XCTAssertEqual(event.group, .action) XCTAssertEqual(data.user, "alice") } // Fire the event from production code under test. LoginEvent.loginSucceeded.fire(on: handler, data: .init(user: "alice", timestamp: .now)) waitForExpectations(timeout: 1) } func testGlobalMetadataTracked() { let handler = AnalyticsSingleExpectationHandler() expect(event: "loginFailed", on: handler) { (event: LoginFailureReason.Event, data: LoginFailureReason) in XCTAssertEqual(data.reason, "wrong_password") } LoginFailureReason(reason: "wrong_password").send(to: handler) waitForExpectations(timeout: 1) } } ``` -------------------------------- ### Define Custom Analytics Event Source: https://github.com/swiftylab/swiftanalyticskit/blob/main/Sources/Analytics/Analytics.docc/Analytics.md Implement AnalyticsEvent to create custom events with associated metadata. Use the .fire() method to send events through an AnalyticsHandler. ```swift enum LoginEvent: String, AnalyticsEvent { case loginAttempted case loginSucceeded case loginFailed struct Metadata: AnalyticsMetadata { let user: String } } let handler = MultiplexAnalyticsHandler() LoginEvents.loginAttempted.fire(on: handler, data: .init(user: "user")) ``` -------------------------------- ### Use StandardDictionaryEncoder for Testing Analytics Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Utilize the StandardDictionaryEncoder from AnalyticsMock for testing purposes. It serializes AnalyticsMetadata to [String: Any] using JSONEncoder and JSONSerialization. ```swift import AnalyticsMock import Analytics struct CheckoutMetadata: AnalyticsMetadata { let orderId: String let total: Double let currency: String } let encoder = StandardDictionaryEncoder( keyEncodingStrategy: .convertToSnakeCase, outputFormatting: [.sortedKeys] ) let metadata = CheckoutMetadata(orderId: "ORD-42", total: 99.95, currency: "USD") let params = try encoder.encodeMetadata(metadata) // params == ["currency": "USD", "order_id": "ORD-42", "total": 99.95] print(params) ``` -------------------------------- ### Define and Fire Events with Empty Metadata Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Use `EmptyRawRepresentableAnalyticsEvent` for events that do not require any metadata, simplifying the event definition. The `group` can be optionally overridden. ```swift import Analytics enum UIEvent: String, EmptyRawRepresentableAnalyticsEvent { case buttonTapped case screenDismissed case refreshPulled // Optionally override group; default is .action. var group: AnalyticsGroup { .action } } // Fire with no metadata argument at all. UIEvent.buttonTapped.fire(on: handler) UIEvent.screenDismissed.fire(on: handler) ``` -------------------------------- ### StandardDictionaryEncoder Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt A pre-built AnalyticsEncoder from the AnalyticsMock module that converts AnalyticsMetadata into a [String: Any] dictionary using JSONEncoder and JSONSerialization. Suitable for testing. ```APIDOC ## StandardDictionaryEncoder (AnalyticsMock) ### Description A ready-made `AnalyticsEncoder` from the `AnalyticsMock` module that uses `JSONEncoder` and `JSONSerialization` to produce `[String: Any]`. Intended for test targets. ### Initialization ```swift StandardDictionaryEncoder( keyEncodingStrategy: JSONEncoder.KeyEncodingStrategy = .useDefaultKeys, outputFormatting: JSONEncoder.OutputFormatting = [] ) ``` - `keyEncodingStrategy`: Strategy for encoding keys (e.g., `.convertToSnakeCase`). - `outputFormatting`: Formatting options for the JSON output (e.g., `.sortedKeys`). ### Method ```swift func encodeMetadata(_ data: T) throws -> [String: Any] ``` - Encodes the provided `Encodable` data into a `[String: Any]` dictionary. ### Usage Example ```swift struct CheckoutMetadata: AnalyticsMetadata { let orderId: String let total: Double let currency: String } let encoder = StandardDictionaryEncoder( keyEncodingStrategy: .convertToSnakeCase, outputFormatting: [.sortedKeys] ) let metadata = CheckoutMetadata(orderId: "ORD-42", total: 99.95, currency: "USD") let params = try encoder.encodeMetadata(metadata) // params == ["currency": "USD", "order_id": "ORD-42", "total": 99.95] print(params) ``` ``` -------------------------------- ### AnalyticsGroup Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt An OptionSet for categorizing events to enable selective routing by multiplex handlers. ```APIDOC ## AnalyticsGroup ### Description An `OptionSet` that categorises events so multiplex handlers can selectively route them. Ten built-in groups are provided; custom groups can be created from any raw `UInt` bit. ### Built-in Groups `.trace`, `.debug`, `.info`, `.action`, `.state`, `.notice`, `.warning`, `.error`, `.critical`, `.sensitive` ### Usage ```swift import Analytics // Combine groups with set literals. mux.register(handler: warningHandler, for: [.warning, .error, .critical]) // Create a custom group. extension AnalyticsGroup { static let purchase: Self = .init(rawValue: 1 << 10) static let onboarding: Self = .init(rawValue: 1 << 11) } enum PurchaseEvent: String, EmptyRawRepresentableAnalyticsEvent { case itemAddedToCart case checkoutStarted case orderPlaced var group: AnalyticsGroup { .purchase } } mux.register(handler: revenueHandler, for: .purchase) PurchaseEvent.orderPlaced.fire(on: mux) // → only revenueHandler ``` ``` -------------------------------- ### ThrottleConfiguration Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt A throttle configuration that drops events fired within a specified interval of the last fired event. This is useful for limiting the rate of event processing. ```APIDOC ## ThrottleConfiguration ### Description Implements `AnalyticsConfiguration` to drop events fired within a specified interval of the last fired event. Useful for rate-limiting event processing. ### Initialization ```swift init(interval: TimeInterval = 0.5) ``` - `interval`: The minimum time interval in seconds between allowed events. ### Method ```swift func process( event: Event, at time: Date = .init(), data: Event.Metadata, for handler: Handler ) where Event.Name == Handler.EventName ``` - Processes an event, potentially dropping it if it falls within the throttle interval. ### Usage Example ```swift enum SearchEvent: String, AnalyticsEvent { case queryChanged typealias Metadata = EmptyMetadata var configuration: AnalyticsConfiguration { ThrottleConfiguration(interval: 0.3) } } ``` ``` -------------------------------- ### ConsoleAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt A simple analytics handler that prints events to the console. Useful for debugging. ```APIDOC ## ConsoleAnalyticsHandler ### Description A simple analytics handler that prints events to the console. Useful for debugging. ### Usage ```swift import Analytics import Foundation struct ConsoleAnalyticsHandler: AnalyticsHandler { typealias EventName = String func track( event: Event, at time: Date, data: Event.Metadata ) where Event.Name == String { let encoder = StandardDictionaryEncoder() let params = (try? encoder.encodeMetadata(data)) ?? [: ] print("[\(time)] \(event.name) [\(event.group)] — \(params)") } } let console = ConsoleAnalyticsHandler() LoginEvent.loginSucceeded.fire(on: console, data: .init(user: "alice", timestamp: .now)) // → [2024-01-15 12:00:00] loginSucceeded [action] — ["user": "alice", "timestamp": ...] ``` ``` -------------------------------- ### Configure MultiplexAnyAnalyticsHandler for Older Platforms Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Use MultiplexAnyAnalyticsHandler for routing events to multiple backends, similar to MultiplexAnalyticsHandler, but with type-erasure for events and metadata. This makes it compatible with Swift versions older than 5.7 and platform versions prior to iOS 16. Note that type-based assertions in individual handlers might be affected. ```swift import Analytics var mux = MultiplexAnyAnalyticsHandler() mux.register(handler: consoleHandler, for: .action) mux.register(handler: fileLogger, for: [.warning, .error, .critical]) LoginEvent.loginFailed.fire(on: mux, data: .init(user: "charlie", timestamp: .now)) // → consoleHandler (action) + fileLogger (not fired — loginFailed is .action, not .warning/.error) ``` -------------------------------- ### Create AppContainer with AnyAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Use AnyAnalyticsHandler to create a type-erased wrapper for an analytics handler. This is beneficial when you need to store heterogeneous handlers in a collection or pass a handler through an API without exposing its concrete type. ```swift import Analytics struct AppContainer { // Store a type-erased handler without exposing the concrete type. let analytics: AnyAnalyticsHandler init(handler: H) where H.EventName == String { self.analytics = AnyAnalyticsHandler(with: handler) } } let container = AppContainer(handler: ConsoleAnalyticsHandler()) LoginEvent.loginAttempted.fire(on: container.analytics, data: .init(user: "bob", timestamp: .now)) ``` -------------------------------- ### Define and Send Global Analytics Metadata Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Use `GlobalAnalyticsMetadata` when event and payload are coupled. Calling `send(to:)` on the metadata value fires the associated event. The event type can be declared inline, and the group can be customized using `.some(group:)`. ```swift import Analytics struct LoginFailureReason: GlobalAnalyticsMetadata { let reason: String let code: Int // The event is declared inline; SomeStringAnalyticsEvent erases the event type. var event: SomeStringAnalyticsEvent { "loginFailed" } } struct UserProfileData: GlobalAnalyticsMetadata { let name: String let email: String // Use .some(...) factory to customise group without a separate event type. var event: SomeStringAnalyticsEvent { .some(group: .info) } } // Send metadata — the associated event is fired automatically. LoginFailureReason(reason: "wrong_password", code: 401).send(to: handler) UserProfileData(name: "Alice", email: "alice@example.com").send(to: handler) ``` -------------------------------- ### MyDictionaryEncoder Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt A custom AnalyticsEncoder that serializes AnalyticsMetadata into a [String: Any] dictionary using JSONSerialization. This is useful for handlers that expect dictionary-formatted parameters. ```APIDOC ## MyDictionaryEncoder ### Description Defines a custom `AnalyticsEncoder` that serializes `AnalyticsMetadata` into a `[String: Any]` dictionary. It uses `JSONEncoder` followed by `JSONSerialization`. ### Method ```swift func encodeMetadata(_ data: T) throws -> [String: Any] ``` - Encodes the provided `Encodable` data into a `[String: Any]` dictionary. - Throws an `EncodingError` if the data cannot be serialized or if the result is not a dictionary. ### Usage Example ```swift struct FirebaseHandler: AnalyticsHandler { typealias EventName = String let encoder = MyDictionaryEncoder() func track( event: Event, at time: Date, data: Event.Metadata ) where Event.Name == String { guard let params = try? encoder.encodeMetadata(data) else { return } // Analytics.logEvent(event.name, parameters: params) print("Firebase.logEvent(\("event.name\»), \(params))") } } ``` ``` -------------------------------- ### AnalyticsSingleExpectationHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt An XCTest-integrated handler from AnalyticsMock that registers one XCTestExpectation per event name. The expectation is fulfilled when the matching event fires. ```APIDOC ## AnalyticsSingleExpectationHandler (AnalyticsMock) ### Description An `XCTest`-integrated handler that registers one `XCTestExpectation` per event name. The expectation is fulfilled each time the matching event fires. Only one expectation can be active per event name at a time. ### Initialization ```swift AnalyticsSingleExpectationHandler() ``` - Initializes the handler with a generic `EventName` type. ### Methods #### `expect` ```swift func expect( event: Event.Name, on handler: Handler, validation: ((Event, Event.Metadata) -> Void)? = nil ) ``` - Registers an `XCTestExpectation` for a specific event name. - Optionally takes a `validation` closure to assert on the event and its metadata. ### Usage Example ```swift final class LoginFlowTests: XCTestCase { func testLoginSuccessTracked() { let handler = AnalyticsSingleExpectationHandler() // Register expectation with a validation closure. expect(event: "loginSucceeded", on: handler) { (event: LoginEvent, data: LoginEvent.Metadata) in XCTAssertEqual(event.group, .action) XCTAssertEqual(data.user, "alice") } // Fire the event from production code under test. LoginEvent.loginSucceeded.fire(on: handler, data: .init(user: "alice", timestamp: .now)) waitForExpectations(timeout: 1) } func testGlobalMetadataTracked() { let handler = AnalyticsSingleExpectationHandler() expect(event: "loginFailed", on: handler) { (event: LoginFailureReason.Event, data: LoginFailureReason) in XCTAssertEqual(data.reason, "wrong_password") } LoginFailureReason(reason: "wrong_password").send(to: handler) waitForExpectations(timeout: 1) } } ``` ``` -------------------------------- ### AnyAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt A type-erased wrapper for AnalyticsHandler, useful for storing heterogeneous handlers or passing handlers through APIs without exposing concrete types. ```APIDOC ## AnyAnalyticsHandler ### Description A type-erased wrapper that hides the concrete `AnalyticsHandler` type. Useful when storing heterogeneous handlers in a collection or passing a handler through an API that does not need to know the concrete type. Events and metadata are type-erased to `AnyAnalyticsEvent` and `AnyMetadata` before dispatch. ### Usage ```swift import Analytics struct AppContainer { let analytics: AnyAnalyticsHandler init(handler: H) where H.EventName == String { self.analytics = AnyAnalyticsHandler(with: handler) } } let container = AppContainer(handler: ConsoleAnalyticsHandler()) LoginEvent.loginAttempted.fire(on: container.analytics, data: .init(user: "bob", timestamp: .now)) ``` ``` -------------------------------- ### MultiplexAnyAnalyticsHandler Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Type-erases events and metadata before dispatch, compatible with older Swift versions and platforms. ```APIDOC ## MultiplexAnyAnalyticsHandler ### Description Identical routing semantics to `MultiplexAnalyticsHandler` but type-erases events and metadata before dispatch, making it compatible with Swift < 5.7 and older platform versions. Trade-off: type-based assertions in individual handlers may be impacted. ### Usage ```swift import Analytics var mux = MultiplexAnyAnalyticsHandler() mux.register(handler: consoleHandler, for: .action) mux.register(handler: fileLogger, for: [.warning, .error, .critical]) LoginEvent.loginFailed.fire(on: mux, data: .init(user: "charlie", timestamp: .now)) // → consoleHandler (action) + fileLogger (not fired — loginFailed is .action, not .warning/.error) ``` ``` -------------------------------- ### Define Custom AnalyticsGroup Source: https://context7.com/swiftylab/swiftanalyticskit/llms.txt Extend AnalyticsGroup to create custom event categories beyond the built-in options. These custom groups can then be used when registering handlers with multiplexing analytics instances. ```swift import Analytics // Built-in groups: // .trace, .debug, .info, .action, .state // .notice, .warning, .error, .critical, .sensitive // Combine groups with set literals. mux.register(handler: warningHandler, for: [.warning, .error, .critical]) // Create a custom group (bit 10 onwards). extension AnalyticsGroup { static let purchase: Self = .init(rawValue: 1 << 10) static let onboarding: Self = .init(rawValue: 1 << 11) } enum PurchaseEvent: String, EmptyRawRepresentableAnalyticsEvent { case itemAddedToCart case checkoutStarted case orderPlaced var group: AnalyticsGroup { .purchase } } mux.register(handler: revenueHandler, for: .purchase) PurchaseEvent.orderPlaced.fire(on: mux) // → only revenueHandler ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.