Background execution
Background tracking is the most divergent area between platforms. The state machine, gate, and schema are uniform — but the OS mechanics that keep your app alive differ fundamentally. Beekon picks the right mechanism per platform; you just need to understand what it’s doing so you can debug when it doesn’t.
Android
Section titled “Android”Beekon runs a foreground service typed FOREGROUND_SERVICE_LOCATION (Android 14+) backed by FusedLocationProviderClient. The service holds a partial wake lock for the duration of tracking.
| Mechanism | Role |
|---|---|
FusedLocationProviderClient | the location source — fuses GPS, Wi-Fi, cell, sensor signals |
| Foreground service + notification | satisfies Android 8+ background-location rules; visible to user |
FOREGROUND_SERVICE_LOCATION type | required for Android 14+ to start a location FGS |
SharedPreferences (in.wayq.beekon) | persists tracking intent so a host-driven cold launch can resume |
The foreground notification is required by the platform, not a Beekon design choice. The notification channel id and notification id are SDK-internal constants; the title, body, and status-bar icon are configurable via NotificationConfig — see Configuration.
Cold-launch resume is host-driven
Section titled “Cold-launch resume is host-driven”Android 15+ blocks BOOT_COMPLETED from launching foreground services, and Android has no equivalent to iOS’s Significant Location Change wake. If you want background tracking to survive process death, call Beekon.start() (or resumeIfNeeded() on the wrappers) from your Application.onCreate — the SDK rehydrates the last BeekonConfig and re-arms the gate.
What can still kill the service
Section titled “What can still kill the service”Aggressive OEM battery managers can kill foreground services on devices from Xiaomi, Huawei, Samsung, OPPO, Vivo, and others. The dontkillmyapp.com matrix maps OEM-specific workarounds (auto-start whitelisting, battery-optimisation exemption). Surface those user-facing instructions in your app’s onboarding for affected devices. When the service is killed entirely, Beekon transitions state to Stopped(System); your app calls start() again when appropriate.
Doze and App Standby
Section titled “Doze and App Standby”Android’s Doze mode (device idle) and App Standby (per-app idle) reduce wake-up frequency for backgrounded apps. The foreground service exempts you from most of this, but not all — expect coarser update cadence during deep doze. Beekon’s gate means you simply emit fewer fixes during these periods rather than dropping mid-trip.
iOS background execution is fundamentally about whether your app is alive at all. Beekon’s iOS 17+ stack is a single code path:
CLLocationUpdate.liveUpdates(.default)+ CLBackgroundActivitySession // keeps background delivery alive+ CLServiceSession(authorization: .always) // iOS 18+ only, declared-authorizationCLLocationUpdate.liveUpdates is the async sequence Apple introduced to replace the delegate; CLBackgroundActivitySession is what makes it survive backgrounding. The configuration is fixed at CLLocationUpdate.LiveConfiguration.default — power-profile tuning isn’t exposed publicly. Rate is governed by Beekon’s interval + distance gate.
Significant Location Change
Section titled “Significant Location Change”Beekon runs a Significant Location Change monitor alongside liveUpdates. SLC is the only mechanism that wakes a terminated iOS app from coarse movement; liveUpdates does not.
When SLC wakes your app into a fresh process, the host app drives resume:
- Call
await Beekon.shared.start()early in yourAppinit. - Beekon reads the persisted tracking intent from a
UserDefaultssuite (in.wayq.beekon); if none is saved it falls back to the all-defaultsBeekonConfig.selfManaged(). - The fresh process has a new
statestream — re-subscribe; the latest state replays.
Force-quit by the user permanently disables SLC until the next foreground open — that’s an Apple platform behaviour, not something Beekon controls.
Authorization
Section titled “Authorization”You need Always authorization for background tracking. iOS forces a two-step prompt: WhenInUse first, then Always after the user has used the relevant feature once. Asking for Always straight away is silently denied. Beekon does not drive these prompts — the host app does. See Platform setup.
Sample-app testing
Section titled “Sample-app testing”For end-to-end background validation, the sample apps are the canonical test rigs: beekon-android/sample (Compose) and beekon-ios/Sample (SwiftUI). A real-device 30–60 minute walk with the app backgrounded is the only way to truly verify background reliability — emulators and simulators lie about doze/SLC.