Swift: Push, attestation and crashes
Register devices for push, prove requests come from your real app, and report crashes with the Swift SDK.
Register devices for push, prove requests come from your real app, and report crashes. Every call runs as the client's signed-in user, so your project's policies and row-level security apply. Types and members are listed in source order; each one links to its HTTP endpoint where it maps to one.
#Types and members
SovariaPush
Push notifications for the signed-in app user. Register the token after sign-in:
Sending happens on your server or in a function with the service role key (api.push.send), never from the app.
public final class SovariaPush: @unchecked SendableSovariaPush.register
Register (or move to this user) a push token.
public func register(token: String, platform: String, provider: String? = nil, appId: String? = nil,
topics: [String]? = nil, locale: String? = nil) async throws -> PushDeviceprovider is fcm or apns; the token is tied to the client's device.
SovariaPush.registerAPNs
The APNs device token from didRegisterForRemoteNotificationsWithDeviceToken (sent as hex, provider apns).
public func registerAPNs(deviceToken: Data, platform: String = "", appId: String? = nil, topics: [String]? = nil,
locale: String? = nil) async throws -> PushDeviceSovariaPush.unregister
Drop a token (sign-out, notifications turned off).
public func unregister(_ token: String) async throwsSafe to call twice.
SovariaPush.devices
public func devices() async throws -> [PushDevice]SovariaPush.subscribe
public func subscribe(_ deviceRowId: String, topics: [String]) async throws -> PushDeviceSovariaPush.unsubscribe
public func unsubscribe(_ deviceRowId: String, topics: [String]) async throws -> PushDevicePushDevice
public struct PushDevice: @unchecked SendablePushDevice.id
A property.
public let id: StringPushDevice.platform
A property.
public let platform: StringPushDevice.provider
A property.
public let provider: StringPushDevice.topics
A property.
public let topics: [String]PushDevice.raw
A property.
public let raw: [String: Any]AttestationProvider
Produces platform evidence for an attestation challenge — the fields of POST /api/v1/attest/exchange. Use AppAttestProvider on iOS devices, DebugAttestationProvider on simulators and CI, or your own.
public protocol AttestationProvider: SendableAttestationProvider.evidence
func evidence(challenge: String) async throws -> [String: Any]DebugAttestationProvider
Stands in for a device on simulators and CI. Create the token in the console (Mobile › App attestation › Debug tokens); never ship it in a release build.
public struct DebugAttestationProvider: AttestationProviderDebugAttestationProvider.debugToken
A property.
public let debugToken: StringDebugAttestationProvider.DebugAttestationProvider.init
Create an instance.
public init(debugToken: String)DebugAttestationProvider.evidence
public func evidence(challenge: String) async throws -> [String: Any]AttestationManager
Keeps a valid attestation token and refreshes it before it expires. The client sends it as X-Sovaria-Attestation and fetches a new one after a 401 APP_ATTESTATION_REQUIRED (same as the Dart client).
public final class AttestationManager: @unchecked SendableAttestationManager.provider
A property.
public let provider: AttestationProviderAttestationManager.margin
A property.
public let margin: TimeIntervalAttestationManager.token
The current token, fetching one first when there is none or it is about to expire.
public func token() async -> String?Nil when attestation fails, so requests still go out (the project may only be monitoring).
AttestationManager.refresh
Fetch a new token now; concurrent callers share one request.
public func refresh() async throws -> String?AttestationManager.clear
public func clear()AppAttestProvider
App Attest on devices that support it (iOS 14+), DeviceCheck otherwise. The key id is kept in storage; the first exchange attests the key (attestation), later ones send an assertion over SHA-256(challenge). appId is the bundle identifier registered in the console; set development for debug builds (App Attest's development environment). App Attest doesn't run on the simulator — use DebugAttestationProvider there.
public final class AppAttestProvider: AttestationProvider, @unchecked SendableAppAttestProvider.appId
A property.
public let appId: StringAppAttestProvider.development
A property.
public let development: BoolAppAttestProvider.AppAttestProvider.init
Create an instance.
public init(appId: String, storage: SessionStorage, development: Bool = false, keyName: String = "")AppAttestProvider.evidence
public func evidence(challenge: String) async throws -> [String: Any]Breadcrumb
A step that led up to a crash (a Sovaria request the SDK made, or one you added).
public struct Breadcrumb: SendableBreadcrumb.category
A property.
public let category: StringBreadcrumb.message
A property.
public let message: StringBreadcrumb.timestamp
A property.
public let timestamp: StringBreadcrumb.Breadcrumb.init
Create an instance.
public init(category: String, message: String, timestamp: String = ISO8601DateFormatter().string(from: Date()))SovariaCrashes
App crash reporting. Uncaught NSExceptions and anything you pass to capture(_:) are grouped into issues in the console (Monitor › Crashes). Each report carries the error type, message, stack, the release, the platform and device, the last 50 breadcrumbs and the signed-in user (the server takes the user from the request token).
A fatal crash can't be sent while the process is dying, so it is written to the offline store and sent on the next launch (call install early, with a durable store). Handled capture(_:) reports send in the background.
v1 covers managed crashes (NSException) and capture(_:). Raw POSIX-signal crashes (SIGSEGV/SIGABRT) need a dedicated signal-safe reporter and are a planned addition; capture those paths with capture(_:) where you can.
public final class SovariaCrashes: @unchecked SendableSovariaCrashes.install
Start capturing.
public func install(release: String? = nil, environment: String? = nil, store: OfflineStore? = nil)Pass a durable store (or enable offline first) so a fatal crash survives to the next launch.
SovariaCrashes.uninstall
public func uninstall()SovariaCrashes.addBreadcrumb
Add a breadcrumb (a step that led up to a crash).
public func addBreadcrumb(category: String, message: String)SovariaCrashes.capture
Report a handled error.
public func capture(_ error: Error, handled: Bool = true, tags: [String: String] = [:],
extra: [String: Any] = [:], fingerprint: String? = nil) -> BoolReturns false if crash reporting isn't installed.
SovariaCrashes.flush
Send queued reports now.
public func flush() async