iOS setup
BeekonKit is a Swift package distributed as a signed binary .xcframework. iOS 17 is the minimum — the SDK is built on CLLocationUpdate.liveUpdates plus CLBackgroundActivitySession, with CLServiceSession(authorization: .always) on iOS 18+. Your app interacts with a single Beekon.shared actor.
Add the package
Section titled “Add the package”In Xcode: File → Add Package Dependencies… then paste:
https://github.com/wayqteam/beekon-ios-binary.gitSelect the version (or branch main for latest) and add BeekonKit to your app target.
For SwiftPM-driven projects (Package.swift):
let package = Package( // … platforms: [.iOS(.v17)], dependencies: [ .package(url: "https://github.com/wayqteam/beekon-ios-binary.git", from: "0.0.3"), ], targets: [ .target(name: "App", dependencies: [ .product(name: "BeekonKit", package: "beekon-ios-binary"), ]), ])Info.plist
Section titled “Info.plist”Add usage descriptions and the location background mode. The strings appear in the system permission dialog — write them in your app’s voice.
<key>NSLocationWhenInUseUsageDescription</key><string>Used to show your live position in the app.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key><string>Used to keep tracking your trips when the app is in the background.</string>
<key>UIBackgroundModes</key><array> <string>location</string></array>fetch and processing are not required for v1 — only location.
Authorization flow
Section titled “Authorization flow”Beekon does not request location permission for you. The host app drives the prompt because the right time and copy depend on your UX. You must reach Always authorization before background tracking will work.
- Request
whenInUsefirst — required by iOS before you can ever ask foralways. - After the user has granted
whenInUseand used the relevant feature once, requestalways. iOS will deny silently if you ask too aggressively. - Call
Beekon.shared.start()once authorization isalways.
The sample app at beekon-ios/Sample/LocationPermissionManager.swift shows the canonical two-step prompt — the relevant lines are:
private let manager = CLLocationManager()
func requestWhenInUse() { manager.requestWhenInUseAuthorization() }func requestAlways() { manager.requestAlwaysAuthorization() }Wire these to two buttons in your onboarding rather than firing both at once.
Configure once
Section titled “Configure once”import BeekonKit
@mainstruct MyApp: App { init() { Task { await Beekon.shared.configure( BeekonConfig(intervalSeconds: 30, distanceMeters: 100) ) } } var body: some Scene { WindowGroup { ContentView() } }}There’s no separate initialize() — Beekon.shared is an actor and is auto-initialized. configure is async and non-throwing; it’s a setter and may be called again at any time, including while tracking, to live-tune the gate.
For cold-launch resume after process death, call await Beekon.shared.start() early in the App init. The SDK reads the last persisted BeekonConfig from a UserDefaults suite (in.wayq.beekon) and resumes; if no intent is saved, it falls back to BeekonConfig.default (30s / 100m).
When start() will fail
Section titled “When start() will fail”do { try await Beekon.shared.start()} catch BeekonError.permissionDenied { // user denied or hasn't granted Always — drive the prompt} catch BeekonError.locationServicesDisabled { // Settings → Privacy → Location Services is OFF system-wide} catch BeekonError.storageFailure(let underlying) { // SQLite/filesystem failure — log and surface}See Errors for the full taxonomy and what to do about each.
What happens behind the scenes
Section titled “What happens behind the scenes”The fix stream is CLLocationUpdate.liveUpdates (the modern async API) wrapped in an AsyncStream for callers. CLBackgroundActivitySession is held to keep background delivery alive; on iOS 18+ a CLServiceSession(authorization: .always) is taken alongside it.
A Significant Location Change monitor runs alongside — it’s the only mechanism that can wake your app from terminated state. Beekon persists tracking intent in a UserDefaults suite (in.wayq.beekon) so an SLC-driven relaunch into a fresh process auto-resumes tracking.
- Android setup — if you also ship for Android.
- Background execution — terminated-state wake, foreground-vs-background rules.
- Lifecycle & states — what
Beekon.shared.statewill emit.