Skip to Content
DocumentationSDKiOS (Native)

iOS SDK (Native Swift)

AppSpacer — Asset OTA updates and crash reporting for native iOS apps, distributed as a Swift Package.

Update model: Apple’s App Store guidelines prohibit hot-swapping executable code in native apps. AppSpacer for iOS delivers asset OTA updates — JSON configs, images, string files, remote content — that your app reads from the OTA cache at runtime.


Requirements

Minimum
iOS14.0
macOS12.0
Swift5.9
Xcode15

Installation

Swift Package Manager

In Xcode: File → Add Package Dependencies → enter:

https://github.com/appspacer/appspacer-ios

Or add to Package.swift:

dependencies: [ .package(url: "https://github.com/appspacer/appspacer-ios.git", from: "1.0.0") ]

Initialization

Call AppSpacer.initialize(config:) in your AppDelegate or @main App struct:

import AppSpacer @main struct MyApp: App { init() { Task { await AppSpacer.initialize(config: AppSpacerConfig( apiKey: "your_api_key", appVersion: "1.0.0" )) } } var body: some Scene { WindowGroup { ContentView() } } }

Config Options

PropertyTypeDefaultDescription
apiKeyStringRequiredYour AppSpacer API key
appVersionStringRequiredCurrent app version
updateStrategyUpdateStrategy.onInit.onInit, .background, or .manual
debugLoggingBoolfalseVerbose console logging
crashReportingEnabledBooltrueCapture native crashes

Reading OTA Assets

Always provide a fallback to your bundled resource:

import AppSpacer struct ContentView: View { @State private var config: [String: Any]? var body: some View { Text(config?["greeting"] as? String ?? "Hello!") .task { config = await AppSpacer.readAssetJSON("config/app.json") } } }
// Raw bytes let imageData = await AppSpacer.readAsset("images/banner.png") // UTF-8 string let csvContent = await AppSpacer.readAssetString("data/products.csv")

Manual Update Check

let result = await AppSpacer.checkForUpdates() switch result.status { case .updated: print("Updated \(result.updatedCount) asset(s)") case .upToDate: print("Already up to date") case .noNetwork: print("Offline — will retry on next launch") case .failed: print("Error: \(result.error ?? "unknown")") }

Crash Reporting

Crash reporting is enabled by default. Uncaught exceptions are captured via NSSetUncaughtExceptionHandler and pending reports are flushed on next launch.

// Report a handled error do { try riskyOperation() } catch { await AppSpacer.reportError(error, context: "PaymentFlow") } // Breadcrumbs for crash context AppSpacer.addBreadcrumb("User tapped checkout", category: "navigation") AppSpacer.addBreadcrumb("Payment API called", category: "network", level: .info)

API Reference

MethodDescription
AppSpacer.initialize(config:)Initialize — call once at app startup
AppSpacer.checkForUpdates()Check and download new assets
AppSpacer.readAsset(_:)Read cached asset as Data
AppSpacer.readAssetString(_:)Read cached asset as String
AppSpacer.readAssetJSON(_:)Read and parse cached JSON asset
AppSpacer.clearAssetCache()Delete all cached assets
AppSpacer.cacheSize()Total cached bytes
AppSpacer.reportError(_:context:extra:)Report a handled error
AppSpacer.addBreadcrumb(_:category:level:)Add crash context breadcrumb
AppSpacer.sessionIdCurrent session identifier

Backend Integration

GET /api/sdk/ios/manifest Headers: x-api-key: <your_api_key> Query: app_version, current_bundle_id, install_id POST /api/sdk/ios/report-status Body: { release_id, device_id, app_version, status, error_message }

Send install_id (a stable per-device ID) on every manifest call — it is required for staged-rollout targeting and monthly active-user metering. Report installed/failed back to report-status so egress is billed once per device and failed installs can trigger auto-rollback.

Upload asset bundles from the dashboard with --platform ios.

Last updated on