tracelet_android
Android implementation of the Tracelet background geolocation plugin.
3.8.7
9.5K downloads/mo
#3012 most downloaded on pub.dev
Ikolvi/Tracelet
What this package is like to depend on
Last release 7 days ago
16 Aug 2026
Ships on a steady schedule
a new release about every 8 days
Nearly every release is documented
notes for 155 of 165 stable releases
Nothing withdrawn
no release was ever pulled
6 months old
170 releases · first in 2026
170 releases in the last 12 months
see the full history below
Release timeline
170 releases · Feb 2026 to Aug 2026Releases
latest 60 of 170-
3.8.716 Aug 2026Release notes
Open source →FIX: the pinned native SDK carries the pedestrian pace hysteresis, the stationary wake re-arm and the reduced per-fix log volume; no Dart or plugin change.
FIX: the pinned native SDK carries the battery-budget ladder, the adaptive-sampling idle escape and the always-on stream diagnostics (#393–#397); no Dart or plugin change.
-
3.8.616 Aug 2026 -
3.8.6-alpha.115 Aug 2026 pre-releaseNothing published for this version
-
3.8.515 Aug 2026Release notes
Open source →FIX: the pinned native SDK clears the odometer's distance anchor in
setOdometer(), so a reset counter is no longer re-inflated by the next fix. No Dart or plugin change; the fix arrives with thecom.ikolvi:tracelet-sdkversion this release pins (#387).FIX: the pinned native SDK acquires a first location when a session starts stationary, which is the default pace — previously
start()acquired nothing until the device physically moved. No Dart or plugin change; the fix arrives with thecom.ikolvi:tracelet-sdkversion this release pins (#385).FIX: the pinned native SDK applies
persistModeto geofence ENTER/EXIT records, which previously bypassed it entirely and were persisted and synced underlocationandnonealike. No Dart or plugin change; the fix arrives with thecom.ikolvi:tracelet-sdkversion this release pins (#383). -
3.8.413 Aug 2026Release notes
Open source →FEAT: the foreground-service host API carries
notificationStartedAt,notificationShowTimerandnotificationOnlyAlertOncethrough to the SDK, so the notification's OS-rendered elapsed timer and its alert-once behaviour are configurable from Dart (#376).FIX: events reach the registered headless task when no member of the event fan-out can receive them. After #364 a foreign plugin's FlutterEngine correctly stays out of
MultiEventSender— andonDetachedFromEnginethen removes the primary's own dispatcher, leaving the SDK holding a composite with no members at all while the other plugin's background engine keeps the process alive. Everysend*wasdispatchers.forEach { … }, a no-op on an empty list, andheadlessFallbackbelonged toEventDispatcher, i.e. to the members that had just left: native tracking kept running, Dart received nothing after task removal, and no log line said so.MultiEventSendernow takes the routing decision itself — broadcast when any member can receive, otherwise a single dispatch to the sameHeadlessTaskServiceinstance the per-dispatcher fallbacks use, which also de-duplicates the case where several members hold a deadeventApi— and both transitions are logged on the always-on lifecycle channel. Reproduced with the plugin that actually causes it: firebase_messaging's own background service, whose engine survives task removal (#371). -
3.8.312 Aug 2026Release notes
Open source →FEAT: the telematics host API carries
speedandvaluethrough to Dart, soTracelet.getTelematicsEvents()returns the magnitudes behind each event's normalized severity rather than dropping them at the platform boundary (#367).FIX: a FlutterEngine created by another plugin no longer captures every event for the rest of the process.
isSpawningHeadlessEngine— the flag #358 introduced — identifies only the engines Tracelet spawns itself, so an engine built by firebase_messaging'sFlutterFirebaseMessagingBackgroundService(or flutter_local_notifications, background_downloader, …) took the UI branch, and plugin auto-registration handed its dispatcher a live PigeoneventApi.EventDispatcherreads a non-nulleventApias "a Flutter engine can receive this", sofallback()stopped routing toHeadlessTaskService— and the isolate it delivered to instead had never calledTracelet.onLocation.onDetachedFromEnginethen made it permanent: the primary removes only its own dispatcher from the fan-out, so after task removal the real UI engine died while the foreign engine survived holding delivery, and native tracking ran on with nothing reaching Dart at all. A secondary engine now joins the fan-out only once its own Dart side subscribes, which the native side learns fromrequestStateFlush—PigeonTracelet._ensureEventsRegistered()sends exactly one per isolate, immediately afterTraceletEventApi.setUp(...), and the Pigeon HostApi is registered per messenger, so its arrival names the engine. An engine that never subscribes never joins, and events keep falling through to the registered headless task. Nothing is lost by waiting: before Dart subscribes there is no handler on the other end, so the deferred events were being dropped by that engine anyway. In-process UI engines that do consume events — anflutter_overlay_windowoverlay, say — are unaffected, since subscribing is exactly what they do; the primary still registers at attach, becauseready()and the state flush it triggers both run through it; and a headless engine is still excluded even if its task subscribes to a stream, so this cannot re-open #358 (#364). -
3.8.211 Aug 2026Release notes
Open source →FIX: geofence crossings (and every other event) reach the registered headless task again once a headless engine has run in the process.
onAttachedToEnginecalledregister()for every attaching engine, including headless background isolates, which gave thatEventDispatchera non-null PigeoneventApi— read as "a Flutter engine can receive this" — so each event was posted into an isolate with noonGeofencelistener instead of falling through toheadlessFallback. The headless task receives events throughHeadlessTaskService.dispatchEvent, a different channel entirely, so one transient headless engine was enough to swallow every crossing for the rest of the process. Secondary engines are now told apart byHeadlessTaskService.isSpawningHeadlessEngine, the flag already wrapped around theFlutterEngineconstructor that triggers the attach: an in-process UI engine (EngineGroup, e.g. an overlay) still joins the fan-out, a headless engine is kept out of it. The attach thread cannot make this call even though it looks like it can — Flutter constructsFlutterEngineon the main looper either way — so the decision is recorded on the always-on lifecycle channel instead of DEBUG, which the release build whose report needs it would drop (#358).FIX: a geofence crossing that cannot be delivered to the headless task now reports the drop and names the cause. The registration guard was an
if (isRegistered())repeated at each call site that dropped the event in silence — the worst possible failure for this event, since the crossing is evaluated, logged and persisted natively before delivery, so a bug report showed the fence working perfectly while the app never heard about it, anddispatchEvent's own trace line never appeared because the call was never made. Those guards are now onedispatchToHeadlesshelper (#358). -
3.8.111 Aug 2026Release notes
Open source →FIX: a headless task after task removal could silently never fire — the engine spawn now times out, retries, and reports failures on the lifecycle channel instead of stalling forever, and its pending-event queue is capped instead of growing without limit (#331).
FIX:
requestSyncBodynow falls back to a registered headless sync-body builder instead of posting the SDK default when no foreground builder is registered (#340). -
3.8.008 Aug 2026Release notes
Open source →FIX: the whole config payload is forwarded with its nulls intact rather than substituted with defaults, so
ConfigManager's existing null-skip applies to every section and not only the foreground service (#321).FIX: the foreground-service section of a
setConfig()payload is forwarded with its nulls intact rather than substituted with defaults, soConfigManager's existing null-skip can do its job and a partialsetConfig()leaves the stored notification settings untouched (#320).FEAT: implements the
getCurrentLocationTuninghost API, which reports the location-filter thresholds actually in force in the native processor rather than echoing the configured values (#303). -
3.8.0-beta.206 Aug 2026 pre-releaseRelease notes
Open source →FEAT: implements the
getCurrentLocationTuninghost API, which reports the location-filter thresholds actually in force in the native processor rather than echoing the configured values (#303). -
3.8.0-beta06 Aug 2026 pre-releaseRelease notes
Open source →FEAT: (Android + iOS)
ModeChangeEvent.appliedTuningreports the four thresholds a committed transport mode put in force —distanceFilter,trackingAccuracyThreshold,odometerAccuracyThresholdandmaxImpliedSpeed— and isnullwhen auto-tuning is off or the mode isunknown. Both SDKs already put these on the native mode-change payload in 3.8.0-alpha, butTlModeChangeEventcarried onlymodeandconfidence, so the plugin dispatchers dropped them: an auto-tune was silent for exactly the Flutter apps documented as being able to observe it (#301).FIX: (Android + iOS) turning
autoTuneFromTransportModeoff at runtime now restores the thresholds you configured.applyTransportModeTuningreturned early when the flag was false, before it could restore anything, and the flag does not trigger a processor rebuild — so a session that had auto-tuned towalkingkept the walking thresholds in force indefinitely after the feature was switched off. DisablingenableFusedClassifierhad the same effect, since destroying the classifier means no further mode change ever arrives to undo the tuning (#301).FIX: (Android + iOS)
setConfig()no longer silently drops an active auto-tune. A location-key change rebuilds the location processor from the configured values, but the classifier's committed mode was unchanged, so the tuning was not re-applied until a different mode committed — a user who stayed on foot across thesetConfig()kept the base thresholds whileonModeChangestill reportedwalking. Both SDKs now re-align the processor with the committed mode after any reconfiguration (#301).FIX: (Android + iOS) enabling
enableFusedClassifierthroughsetConfig()while already tracking now starts the ~1 Hz accelerometer-window loop that drives the classifier. It was started only fromstart(), so a mid-session enable produced a classifier that never classified — and, with auto-tuning on, never retuned. Configuring the classifier atready()was unaffected (#301).FIX: (iOS)
autoTuneFromTransportModeis now watched in the behaviour-key comparison that decides whethersetConfig()rebuilds the behaviour engines, matching Android (#301). -
3.8.0-alpha05 Aug 2026 pre-releaseRelease notes
Open source →FIX: (Android + iOS)
useKalmanFilter: truenow affects recorded distance, not just the rendered track. The odometer accumulated raw inter-fix deltas because Kalman smoothing ran after the location processor and fed onlycoords, so enabling the filter visibly smoothed the map while distance kept integrating GPS jitter — over-reporting badly on foot, where noise is large relative to real displacement. Smoothing now runs before the processor on both platforms, so the distance filter, accuracy filter, implied-speed filter and the odometer all operate on the de-noised track. Every fix feeds the filter (not only accepted ones), keeping its velocity estimate continuous across rejections (#299).FIX: (Android + iOS)
fusedClassifierAuthoritative: truenow genuinely drives sampling. The adaptive sampler was built from the raw platform Activity-Recognition value rather than the effective activity, so the fused classifier never reachedAdaptiveSamplingEnginedespite the option being documented as overriding the platform activity for sampling (#299).FIX: (iOS) the
classifierconfig section was dropped entirely when flattening the plugin config, makingenableFusedClassifier— and every other classifier option — undeliverable from Flutter on iOS (#299).FIX: (Android + iOS) a fix too coarse for the odometer now defers its distance instead of deleting it.
odometerAccuracyThresholdblocked such a fix from contributing, but the odometer's reference point advanced anyway — so the ground actually covered during that segment was lost for good, and the tighter the gate the more distance silently went missing. The odometer now keeps its own anchor, advanced only by fixes that clear the gate, so the next trustworthy fix books the whole span it covered. Without this, tightening the gate (which transport-mode auto-tuning does on foot) traded over-reporting for systematic under-reporting (#299).FEAT: (Android + iOS) new
ClassifierConfig.autoTuneFromTransportMode(defaultfalse). When enabled, a committed transport mode retunesdistanceFilter,trackingAccuracyThreshold,odometerAccuracyThresholdandmaxImpliedSpeedfor that mode — tighter on foot, looser in a vehicle — from a table shared by both platforms via the Rust core. This removes the hand-tuning that distance-accurate tracking previously required, and which neither the app developer nor the end user can get right in advance: a single session routinely contains walking, jogging and running. Retuning happens only on a committed change (confidence-gated and debounced bymodeSwitchDwellMs), never per accelerometer window, and swaps thresholds in place so the odometer stays continuous across the change. A mode ofunknownrestores your configured values, and the applied thresholds ride on themodechangepayload so an auto-tune is never silent. RequiresenableFusedClassifier: true(#299). -
3.7.605 Aug 2026Release notes
Open source →FIX: (Android + iOS) high-accuracy geofence ENTER/EXIT transitions no longer intermittently fail to fire for a stationary device. In
geofenceModeHighAccuracythe crossing evaluator is now fed the raw fix stream and the provider is requested with time-based delivery (minUpdateDistanceMeters = 0/kCLDistanceFilterNone), decoupling geofence evaluation from the tracking distance filter. That filter is a persistence-volume control, but it was also gating the fixes reaching the evaluator: a device standing still on a stable provider — GMS FusedLocationProvider (Android, since 3.7.3) or CoreLocation with a distance filter (iOS) — never moves the filter's distance, so no fix was delivered and no transition was evaluated (field logs show an iPhone parked inside a 50 m zone emitting many ENTERs and never an EXIT). Persistence is unchanged — the RustLocationProcessorkeeps its distance filter, so stored/synced location volume does not increase — and the decision logic (accuracy gating #274, 2-fix confirmation #294, hysteresis) is untouched; it simply now sees every fix. Standard OS region-monitoring geofence mode is unaffected (#297). -
3.7.504 Aug 2026Release notes
Open source →FIX: (Android + iOS) a geofence EXIT is now confirmed across
GEOFENCE_EXIT_CONFIRMATIONS(2) consecutive out-of-fence fixes rather than a single one. Consumer GNSS routinely emits an isolated "over-confident" fix — one that lands hundreds of metres outside while reporting a tight accuracy the accuracy-aware gate (#274) cannot see through; field logs from a vivo V2431 and a Samsung SM-G781B show a stationary office device jumping to 198–301 m out at 1.7–9 m reported accuracy and straight back. Such a fix is always transient, so requiring the device to be confidently outside for two consecutive fixes absorbs the glitch on every device, while a genuine departure — which stays outside — still fires exactly one EXIT, delayed only by one fix interval. This is the temporal complement to the spatial exit hysteresis (#268); the decision lives in the Rust core, so Android and iOS inherit it identically, and the pure-Dart evaluator mirrors it (#294). -
3.7.403 Aug 2026Release notes
Open source →FIX: (Android + iOS) in
geofenceModeHighAccuracy, a stationary device inside a geofence no longer emits a false ENTER on every resume/boot.startGeofences()callsclearHighAccuracyState(), which wipes the evaluator's in-memory inside-set, and it runs on everyready()/takeover ("Resuming geofence tracking on ready/takeover") and after boot/task-removal — so on an aggressive OEM it fires many times per hour. After each wipe the next fix satisfiesentered && !was_insideand the evaluator re-emits ENTER; on an attendance backend each becomes a punch-in/punch-out, and a field report showed ~9 auto IN/OUT pairs in a day while the employee never left the office. The exit hysteresis from #268 and the accuracy-aware EXIT from #274/#276 cannot help, because they govern the crossing math within one evaluator lifetime while the "already inside" memory is discarded on every resume — so each takeover looks like a legitimate first-ever ENTER.startGeofences()now takes anisResumeflag: a resume/boot preserves inside-state and only a fresh explicit start resets it (which still re-emits the initial-entry ENTER once). In addition,GeofenceManagerpersists a "known inside" set (SharedPreferences on Android, UserDefaults on iOS) that dedups high-accuracy ENTER/EXIT emissions and survives process death, so even a cold-start re-entry after an OEM kill is suppressed while a genuine departure and return still fire (#292). Finally,startGeofences()is now idempotent — calling it again while already tracking in geofence mode (the common "refresh fences on every app launch" pattern) is treated as a resume and preserves the inside-set, so only a genuine (re)start (first enable, or afterstop()) re-arms the initial-entry ENTER. The persisted set is also kept honest across the full geofence lifecycle: removing a geofence clears its inside-state (so a re-added id, or an id reused for a different location, can ENTER again), and on cold start the evaluator is re-seeded from the persisted set so a device that left a fence while the app was killed reports a real EXIT on the next fix instead of getting stuck inside and suppressing the next genuine ENTER. -
3.7.301 Aug 2026Release notes
Open source →FIX: (Android) minified release builds no longer fall back to the AOSP location stack on devices that have Google Play services.
TraceletServices.isGmsAvailableresolvedGoogleApiAvailabilityreflectively soplay-services-basecould stay a soft dependency, but R8 rewrites theClass.forNamestring literal to the renamed class while leaving thegetMethod("getInstance")argument untouched — so the class resolved, the method lookup threwNoSuchMethodException, and thecatchreported GMS as missing. Field logs show it verbatim:Exception in isGmsAvailable reflection check: v2.d.getInstance []on a Galaxy S23. Every minified build since 3.6.x was therefore running on rawLocationManagerwithGPS_PROVIDER+NETWORK_PROVIDERinterleaved, the deprecatedaddProximityAlert, and a no-op activity-recognition client — feeding coarse network fixes straight into the geofence evaluator, which the accuracy-aware EXIT gating from #274/#276 cannot defend against. The probe now distinguishes "GMS absent" from "the probe could not run": a probe failure falls back to an OS package-manager query that no shrinker can rename, and a-keeprule forGoogleApiAvailabilityships in both consumer ProGuard files so the precise reflective path keeps working in host apps.FIX: geofence ENTER/EXIT transitions are now logged, at
INFO, with the full decision trace on both Android and iOS.evaluateHighAccuracyProximityand the OS-transition handler previously logged nothing at any level, so a report of an occasional false EXIT produced a bug report with zero geofence content and had to be triaged from configuration alone. Each crossing now emits[geofence] EXIT <id> dist= radius= buffer= thr= margin= accRaw= accEff= exitAccuracyMax=, which is what separates a genuine departure from drift: a smallaccRawwith a largedistis an over-confident fix,clampApplied=trueshowsgeofenceExitAccuracyMaxbinding and weakening drift immunity relative to the-1default, andaccuracyInvalid=true gatingDisabled=trueflags a fix with no valid accuracy (negativehorizontalAccuracyon iOS,0.0on Android), which the evaluator treats as zero uncertainty. The line carries distance-from-centre rather than coordinates, so it is safe to paste into an issue. The OS/AOSP path logssource=osand states that it has no accuracy gating, andupdateProximitynow labels its line "not ENTER/EXIT" — it reports monitoring scope, and apps that readgeofencesChange.offas an exit will see phantom exits from a single far-drifting fix.FEAT:
TraceletBugReportgained a Geofence transitions (decision trace) section that lifts[geofence]lines out of the general log stream and scansgeofenceTraceLimit(2000) entries rather than the 500-entry log window. Crossings are rare while lifecycle chatter is not, so in a busy app the transitions were being pushed out of the exported window before anyone generated a report.PERF: the native loggers no longer run a
DELETEafter every log write. Retention is 500-2000 rows, so pruning is now amortized every 50 writes on both platforms. -
3.7.201 Aug 2026Release notes
Open source →FIX: (smart motion)
start()seeds the coordinator's accelerometer flag and re-syncs its tracking mode, so the accelerometer can contribute to a stationary decision after a start that begins in MOVING (#288).FIX: (smart motion)
MotionDetectorno longer writesisMovingitself in smart mode, where the coordinator owns the decision (#288).FIX:
shakeThreshold,stillThresholdandstillSampleCountare only forwarded to the native SDK when the app set them, so platform-tuned defaults survive (#288).FIX: a still device now reaches STATIONARY on schedule instead of being stranded in MOVING. While the speed state machine counted down in SLOWING, a single GPS fix at or above
speedMovingThresholdcancelled the countdown and restarted the wholespeedStationaryDelaywindow. GPS speed is noisy on a stationary device — an isolated1.56 m/sblip amid a stream of0.00 m/sfixes was enough — so the pace could keep restarting its countdown indefinitely while the accelerometer had already reported sustained stillness. SLOWING now requires three consecutive above-threshold fixes before returning to MOVING (the same sustained-motion remedyMotionDetectorapplies to accelerometer noise) and the countdown keeps its original start time across a blip. Safe by construction: SLOWING is still continuous tracking, so confirming over a couple of fixes costs no location fidelity. Applied on Android and iOS (#288).FIX: the
tracelet_syncsink is now process-wide instead of one perFlutterEngine. Both native plugins created a newTraceletSyncSinkon every engine attach and never detached one, so any host that spawns secondary engines —workmanagercreates one per background task, plus headless engines and engine groups — accumulated sinks for the life of the process. Each sink owns its own concurrency guard (aCoroutineScope+Mutexon Android, aSyncCoordinatoractor on iOS), so those guards stopped serializing anything and a single persisted location fanned out into N blocking auto-syncs, each pinning one or two threads:OutOfMemoryError: pthread_create failed, heap exhaustion, duplicate points server-side and racingclearLocationsUpTocalls. The sink is now created once and reused by every later engine, and it is deliberately kept alive on detach so native/headless tracking keeps syncing after a short-lived engine goes away. On iOS the plugin also stopped subscribing the sink twice per engine (directly and through thesyncProviderdidSet) and gained adetachFromEngine(for:)hook (#286).FIX: (iOS) a superseded sync provider can no longer stay subscribed to the
LocationEngine.registerSinkwas a bare append with no dedupe and there was no way to remove a sink at all, so duplicate and stale sinks each fanned out anotherinsertLocationfor the same fix.registerSinknow dedupes by identity,unregisterSinkwas added (Android has had both since #204), andTraceletSdk.syncProvidercancels and unregisters the provider it replaces (#286). -
3.7.129 Jul 2026Release notes
Open source →FIX:
locationSourceandreducedAccuracyare no longer dropped from persisted and synced locations. Both fields are emitted on the liveonLocationevent, but the persist path only serializedaudit_*,batteryandextrasinto theroute_contextcolumn, so the classification was lost at write time — every DB-sourced read (getLocations,getPendingLocations) and the DB-sourced sync payload (setSyncBodyBuilder) reportedlocationSource: "unknown"/reducedAccuracy: false. This broke the documented guidance to filter historical/synced fixes bylocationSource == "gps". Both fields are now persisted as first-classroute_contextkeys (likeaudit_*) and promoted back to the top level byLocationMapperon read; because the PigeonTlLocationboundary has no dedicated fields for them, they are carried across it viaextras(like the live event) and unpacked byLocation.fromMap, so the live event and DB-sourced reads agree. Applied on Android and iOS (#280).FIX: (iOS) high-accuracy periodic fixes are no longer a single
requestLocation()one-shot, which frequently returned a stale cached or first-coarse fix before the GPS hardware converged (persisting a Wi-Fi/cell-level fix for a periodic tick). WhenperiodicDesiredAccuracyisDesiredAccuracy.high,performPeriodicFix()now routes through the same best-of-N sampling windowgetCurrentPositionalready uses (collectSamples→ most-accurate sample), bounded bylocationTimeout, so periodic fixes are GPS-quality. Non-high periodic accuracy keeps the cheaper single-shot path, and overlapping ticks are guarded against (#282). -
3.7.029 Jul 2026Release notes
Open source →FEAT(geofence): accuracy-aware geofence EXIT for high-accuracy mode. A circular geofence now only fires EXIT once the entire GPS error circle clears the fence (
distance - accuracy > radius + buffer), so a single high-drift, low-confidence fix no longer produces a false EXIT while a device is stationary inside a small geofence. ENTER stays accuracy-agnostic so arrivals still trigger promptly (#274).FEAT(geofence): new
GeofenceConfig.geofenceExitAccuracyMax(meters) to tune the accuracy-aware EXIT gating —-1full gating (default, most drift-resistant),0disables gating (fastest, most eager EXIT), andN > 0clamps the accuracy used in the exit test toNto bound the worst-case exit delay while still absorbing drift up toN. High-accuracy path only; no effect in standard OS region-monitoring mode (#276). -
3.6.1528 Jul 2026Release notes
Open source →FIX: (Android) geofence transitions and confirmed crash/fall deliveries could be silently dropped right after a cold boot. Since #260 moved the heavy
initialize()setup (Rust DB open,lateinitgeofenceManager/engines) onto a background thread,initialize()returns before those managers exist. #264 guarded theready()/bootstrapForBackground()paths, but the native broadcast entry points still raced init:GeofenceBroadcastReceiverreadgeofenceManagerimmediately afterinitialize()(so a cold-boot ENTER/EXIT — a trip start — was swallowed and lost), andCrashConfirmReceiverdelivered a confirmed impact onto not-yet-wired state. Both now funnel through a newawaitInit()gate that blocks until init completes (or reports failure/timeout) before touching those managers, so the transition/impact is delivered instead of dropped. iOS is unaffected (itsinitialize()is synchronous) (#271). -
3.6.1427 Jul 2026Release notes
Open source →FIX: geofence
ENTER/EXITflapping for a stationary device inside the radius (high-accuracy mode). The evaluator used a singledistance <= radiusthreshold for both entry and exit, so a motionless device whose GPS fixes jittered across the boundary emitted repeatedENTER/EXITevents. Exit now applies hysteresis — the deviceENTERs at the true radius but onlyEXITs once it is farther thanradius + max(radius * 0.1, 20 m)from the center — so boundary jitter no longer flips the state. Applied in both the pure-Dart evaluator (the active high-accuracy path) and the Rust core used by the native SDKs (#268).FEAT: (Android) add
Tracelet.requestTermination()to stop the GPS foreground service from a headless Dart isolate. When an FCM silent push runs a background task while the app is terminated,Tracelet.stop()is unavailable because it relies on Pigeon, which headless isolates cannot reach — so the foreground service kept polling and draining battery until the app was reopened. A newrequestTerminationhandler on thecom.tracelet/methodsMethodChannel (registered on the headlessFlutterEngine) callsTraceletSdk.stop(), letting background handlers shut tracking down cleanly (#267). -
3.6.1326 Jul 2026Release notes
Open source →FIX: (Android) prevent a runtime crash when
com.google.android.gms:play-services-locationresolves below 21.2.0. Tracelet's Android bytecode calls the interface-basedFusedLocationProviderClientandActivityRecognitionClientAPIs, which only became interfaces in play-services-location 21.2.0. When a host app resolved an older version (e.g. 19.0.0) transitively, those types were still concrete classes, so calling into them threwjava.lang.IncompatibleClassChangeError(crashing the periodic location worker and, after permission handling, the main thread). play-services-location stayscompileOnly, so the SDK still degrades gracefully to the AOSPLocationManagerwhen GMS is absent; a published Gradle dependency constraint now raises the resolved version to a compatible floor (>= 21.2.0) whenever the dependency is present, without adding it to the dependency graph (#263).FIX: (Android) prevent a boot/restart crash with
UninitializedPropertyAccessException: lateinit property geofenceManager has not been initialized. WithstartOnBoot: trueandstopOnTerminate: false,LocationService.startBootTracking()calledbootstrapForBackground()and then immediately accessed thegeofenceManager. Since 3.6.9,initialize()runs on a backgroundtracelet-initthread andbootstrapForBackground()did not wait for it, so on a cold boot thelateinitmanagers could still be unassigned — crashing the service inonStartCommandbefore the foreground notification was posted (a timing race most reliably seen on slower environments such as emulators).bootstrapForBackground()now blocks on the init latch and returns a success flag: it preserves the initialization exception (no longer mistaking a released latch for success) and verifies the Rust DB andgeofenceManagerare actually assigned.startBootTracking()defers gracefully without touching any manager, andPeriodicLocationWorkerreturnsResult.retry(), when initialization has not completed (#264).FIX: (Android)
Tracelet.addGeofence()no longer returnsfalsefor a geofence that was actually registered. When no device location is known yet,addGeofence()persists the record and callsregisterGeofence(), whose Google Play Services registration is asynchronous. The Flutter host calls this on the main thread, where the SDK correctly does not block on the registration callback — but it then returned the still-falseresult before the callback ran, so apps saw a bogus failure even thoughgetGeofences()listed the geofence. On the main thread the SDK now returnstrueonce the registration request has been scheduled without a synchronous error (off the main thread it still awaits the real callback result); genuine Play Services failures continue to be logged. iOS and web were unaffected (#265). -
3.6.1226 Jul 2026Release notes
Open source →FIX:
Tracelet.ready()no longer surfaces remote-config event registration failure as an uncaught async error. Since 3.6.10,ready()subscribes toremoteConfigEvents, which lazily registers the Pigeon event channel and firedrequestStateFlush()fire-and-forget. When the platform side was unreachable (e.g. a headlessflutter testwith no channels, or a temporarily detached engine), the rejected future became an uncaught async error routed to the zone error handler instead of one the caller'sawait ready(...)could catch — fatal for a ride-start path that wrappedready()in try/catch and still got torn down. The best-effort flush is now awaited inside a guarded helper that contains any failure, so it can never escape as an uncaught async error; event registration itself already succeeded, so nothing observable is lost and callers can always recover (#262). -
3.6.1125 Jul 2026Release notes
Open source →FIX: (iOS)
IosConfig.useSignificantChangesOnlyno longer keeps the persistent system location indicator on. On iOS 17+, enabling significant-change monitoring and callingTracelet.start()still showed an ongoing location indicator (Dynamic Island / status-bar pill) becausestart()opened aCLBackgroundActivitySessionwhenever the device was moving, even though continuous GPS was correctly skipped.CLBackgroundActivitySessionholds a background location activity alive and auto-shows the indicator, defeating the whole point of significant-change monitoring (low-power background location with no persistent indicator). The SDK now fully honors significant-changes-only mode — it neither opens aCLBackgroundActivitySessionnor starts continuous GPS (startUpdatingLocation), which independently light up the system location indicator — acrossstart(), the motion-detection pipeline's switch-to-continuous,changePacetransitions, and killed-state auto-resume, matching the existing behaviour of periodic mode and low-accuracy geofence-only mode. High-accuracy geofencing and the explicitIosConfig.useBackgroundActivitySessionopt-in are unaffected. The indicator may still blink briefly when a significant-change event is delivered, which is normal iOS behaviour. (#261) -
3.6.1024 Jul 2026Release notes
Open source →FIX: Remote configuration overrides (Enterprise
remoteConfigUrl) now propagate to the Dart layer. Remote config is fetched and applied entirely on the native side; previously the result never crossed back to Dart, soTracelet.activeConfig— and anything reading it, such astracelet_doctorand the Dart-side battery-budget engine — kept showing the last locally-set values (e.g. a remotely fetchedbatteryBudgetPerHourof1.0never appeared, while a localsetConfigvalue did). The native layer now emits anonRemoteConfigevent whenever it applies a remote override — both the freshly fetched config and the cached copy restored atready()— and the Dart layer folds it into the active config, re-initialising the Dart-side battery-budget engine. A newTracelet.onRemoteConfig(...)callback andTracelet.remoteConfigStreamlet apps react to server-driven configuration changes. -
3.6.924 Jul 2026Release notes
Open source →FIX: Remote config (and any runtime
setConfig()) now appliesbatteryBudgetPerHour. The battery-budget engine was only built duringready(), so a remote-config push such as{"geo":{"batteryBudgetPerHour":1.0}}delivered at runtime viasetConfig()was stored but never acted on — it only appeared to work after a cold restart (which applies the cached copy beforeready()builds the engine). The engine is now rebuilt whenbatteryBudgetPerHourchanges at runtime on both Android and iOS, and battery-budget sampling is started or stopped to match the live tracking state.FIX: iOS — all
Doubleconfiguration getters now read throughNSNumber, so integer-encoded values (e.g.1instead of1.0from a remote-config JSON endpoint, or a plain SwiftInt) coerce correctly instead of silently falling back to their defaults. This matches the existing Android coercion behaviour.FIX: Android —
initialize()now runs its heavy setup (opening the Rust database, whichfsyncs to disk) on a background thread instead of the caller's main thread, andready()waits for it to finish. Previously, when the system re-created a backgroundFlutterEngine(e.g.audio_service's media service after the app was killed),GeneratedPluginRegistrantre-attached the plugin and the diskfsyncran on that service's main thread, causing an ANR on databases grown large over days of tracking. Thanks to @dagovalsusa (#260). -
3.6.823 Jul 2026Release notes
Open source →FEAT: Expose
Tracelet.updateNotification(), a public API to refresh the active Android foreground-service notification after changing its configuration (#257). The foreground-service notification is configured throughForegroundServiceConfig(title, text, icon, color, actions, priority, ongoing state), but there was previously no public way to apply notification-only changes to an already-running service — a notification-onlysetConfig()did not repost the live notification, so new content only appeared after an unrelated service restart or foreground transition.updateNotification()now refreshes the active on-screen tracking indicator from the latest configuration without restarting the tracking pipeline. On Android theACTION_UPDATE_NOTIFICATIONservice path rebuilds and reposts the foreground-service notification (previously a no-op) when the service is promoted, and is a safe no-op when the service is not running. iOS has no foreground-service notification, soupdateNotification()instead refreshes the running Live Activity — when the app opted into one vialiveActivityConfig— from the latest config (the dynamic body; the title is immutable on a running activity), and is a safe no-op otherwise. Web is a no-op. -
3.6.723 Jul 2026Release notes
Open source →FIX: In
MotionDetectionMode.smart/.speed,setConfig()could restore a temporary stationary mode as the main tracking mode. Those modes run a single continuous motion-aware pipeline that temporarily flips the tracking mode to periodic/geofences while the device is stationary. A restart-sensitivesetConfig()captured that temporary tracking mode and rebuilt the pipeline via the standalonestartPeriodic()/startGeofences()paths, tearing down the motion-detection pipeline that switches back to continuous on movement — stranding tracking in a standalone stationary mode.setConfig()(and, on iOS,ready()'s resume path) now restarts the continuous motion-aware pipeline viastart(isResume: true)whenever the motion-detection mode is smart/speed, regardless of the temporary tracking mode; the pipeline re-enters the stationary sub-state on its own when still stationary. Fixed on both Android and iOS (#256). -
3.6.622 Jul 2026Release notes
Open source →FEAT: Added
Tracelet.getForegroundServiceHealth()— exposes the authoritative native foreground-service state (whether the service is running and promoted to the foreground, the last promotion result ofsuccess/deferred/failedwith its failure class and message, the notification id, and the last transition timestamp) alongside the desiredenabledstate. On Android 12+ a foreground-service start can be deferred or rejected by the OS even while tracking is enabled, soenabledalone is not proof that background tracking is operational; this lets apps build accurate tracking-health indicators, diagnostics, and recovery. iOS reports the desired state with null/false promotion fields (it has no foreground service), and web returns a minimal disabled map (#255).FIX: On Android, changing a restart-sensitive setting via
setConfig()while tracking with a foreground service could kill that service. The restart path called the fullstop()— which sendsACTION_STOPtoLocationService(stopForeground+stopSelf) — and immediately restarted the pipeline withACTION_START. On a fresh promotion theACTION_STOPhandler'sstopSelf()could win the race and destroy the service right afterACTION_STARTpromoted it, leaving no foreground service at all — the same race fixed forstartPeriodic()in #237.stop()now accepts apreserveForegroundServiceflag and thesetConfig()restart path keeps the service alive whenever the target mode still needs it, letting the idempotentACTION_STARTre-assert foreground with no gap; modes that do not use the service stop it cleanly with no follow-up start to race. iOS is unaffected (#254). -
3.6.521 Jul 2026Release notes
Open source →FIX: On Android a failed foreground promotion no longer leaves the service marked as a running foreground service.
LocationService.startForegroundWithNotification()catches astartForeground()failure and tears the service down (stopForeground+stopSelf+isRunning = false), but because the exception was swallowed, execution returned normally and every caller then setisForegroundService = trueunconditionally. The method now returns whether the promotion succeeded and all callers gateisForegroundServiceon that result, so a failed promotion leaves the flagfalse. iOS is unaffected — it has no foreground-service promotion that can fail after the fact (#253). -
3.6.420 Jul 2026Release notes
Open source →FIX: On iOS the heartbeat writer no longer persists a GPS fix that the normal dispatch already stored, so
getLocations()no longer returns byte-identical duplicate location rows (roughly half the points of a moving trip were duplicated on-device). The normal dispatch persists withevent="location"and the heartbeat timer re-tagged the same cached fix withevent="heartbeat"and inserted it again; the dedup guard only skipped repeats forevent="location", so the heartbeat write slipped through. The guard now shares one last-inserted-timestamp key across both writers. The Android guard is kept in parity (#252). -
3.6.319 Jul 2026Release notes
Open source →FIX:
destroyLocation(uuid)now deletes the record addressed by its public UUID on both Android and iOS. Previously both native SDKs parsed the UUID string as a numeric database id (toLongOrNull()/Int64(uuid)), so any real UUID failed to parse and the call returnedfalsewithout deleting anything — pending locations could never be acknowledged and the queue never drained. The UUID is now resolved to its row id before deletion, with the legacy numeric-id path kept for backward compatibility (#251).FIX:
IosConfig.activityTypeis now applied toCLLocationManageras configured on iOS. Two independent bugs previously made every value resolve to.otherNavigation: the Dart bridge mapped between two differently-ordered enums by raw index (so e.g.otherNavigationwas sent asfitness), and the native side stored the value as an Int but read it back as a String and always fell through to the default. Both sides now agree, soautomotiveNavigation/fitness/airbornetake effect (#250). -
3.6.218 Jul 2026Release notes
Open source →FEAT: Remote config (
remoteConfigUrl) is now fetched and applied natively on iOS and Android. Onready()the SDK fetches a JSON config map from your HTTPS endpoint, applies it over the local config (restarting the tracking pipeline when a tracking-relevant key changes), and refreshes it in the background on theremoteConfigRefreshIntervalcadence. The last successful response is cached to disk, so a restart resumes on the freshest known settings instantly and offline. Only HTTPS URLs are honored. Previously both platforms recognized the field but never fetched it — the native side silently fell back to the local config.FIX: Stop double-inserting stationary periodic fixes with the same uuid. The stationary periodic timer in
LocationServicenow passespersist=falsetogetCurrentPosition()so it stays the single writer of the enriched "periodic" record (and the single event dispatch). Fixes the "UNIQUE constraint failed: location_events.uuid" error that occurred every stationary tick (#248). -
3.6.117 Jul 2026Release notes
Open source →FIX: Explicit
GeofenceConfig(geofenceModeHighAccuracy: false)is now honored on aggressive OEMs (Samsung/Xiaomi/Huawei/OnePlus/Oppo/Vivo) instead of being silently forced totrue— which madestartGeofences()start the location engine and theLocationServiceforeground service with its persistent notification, the exact thing low-accuracy geofences-only mode exists to avoid (and which Google Play prohibits solely for geofencing from 2026-10-28). Consistent with the #243 fix, the configured value is authoritative on every device and the SDK logs a reliability warning instead (#247). -
3.6.016 Jul 2026Release notes
Open source →FEAT:
Tracelet.updateLocationProviderOptions()— temporarily overridedesiredAccuracy/distanceFilteron the running OS provider without a pipeline restart; ephemeral (cleared bystop()), persisted config untouched. Live on iOS (CLLocationManagerproperty update) and Android (callback-preserving fused re-subscription) (#241).FIX: Explicit
foregroundService.enabled: false/periodicUseForegroundService: falseare now honored on aggressive OEMs (Xiaomi/Huawei/Samsung/OnePlus/Oppo/Vivo) instead of being silently forced back on with the default foreground notification; the SDK logs a reliability warning instead. Leftover foreground services are also torn down when switching to a no-service periodic strategy, and sticky service restarts re-validate state/config before re-posting the notification (#243).FIX:
rejectMockLocationsnow guards every Android delivery path —getCurrentPosition()(including the last-known fallback),watchPosition(), and periodic fixes — not just continuous tracking (found auditing #243).FIX: iOS
buildLocationMaphardcodedactivity: {type: "unknown", confidence: -1}on every persisted/dispatched location, dropping the classified transport mode even withfusedClassifierAuthoritative: true. Per-pointactivitynow carries the effective mode and confidence (fused when authoritative, scaled 0–100; otherwise platform Activity Recognition), including on the dead-reckoning path, and Android pairs the authoritative fused type with the fused confidence instead of the unrelated AR confidence (#244).FIX: Fused transport modes are persisted in the Activity Recognition vocabulary on both platforms (
vehicle→in_vehicle,cycling→on_bicycle), and the DartLocation.activity.typeparser now accepts the native snake_case strings —in_vehicle/on_bicycle/on_footpreviously collapsed toActivityType.unknown(follow-up to #244).FIX:
activity.confidencenow survives the DB round-trip — newactivity_confidencecolumn in the location store (auto-migrated;-1for rows persisted before the column existed), stored on every insert including encrypted payloads, and returned bygetLocations()and the sync-interceptor sink instead of a hardcoded100(#245). -
3.5.713 Jul 2026Release notes
Open source →FIX: Build fails without AGP built-in Kotlin (AGP <9 / builtInKotlin=false) (#239).
-
3.5.609 Jul 2026Release notes
Open source →FIX: Custom sync body 400 Bad Request HTTP errors now gracefully return fallback results instead of propagating fatal exceptions in native Sync engines (#238).
-
3.5.507 Jul 2026Release notes
Open source →FIX: Ensure foreground service is properly started in periodic mode when configured (#237).
-
3.5.430 Jun 2026Release notes
Open source →FIX: Enrich geofence transition events with real coordinate metrics (accuracy/speed/heading/altitude) from the last GPS fix and attach the battery snapshot, instead of hardcoded zeros (#231). FIX: Propagate runtime
setConfigchanges to the active native tracking/sensor loops by performing a clean full-pipeline restart (location + motion/speed) when a tracking-relevant key changes (#230). FIX: Null-guard subsystems indestroyAll()so engine/Activity teardown never throws when the SDK was never initialized (fatalUnable to destroy activity) (#227). FIX: Android: standard geofence mode no longer starts a foreground service, complying with Google Play's policy (effective 2026-10-28) that prohibits using a foreground service solely for geofencing. Native geofences keep firing while the app is suspended/terminated; geofence-only apps can removeFOREGROUND_SERVICE_LOCATIONfrom their manifest. -
3.5.330 Jun 2026Release notes
Open source →FIX: Added explicit ProGuard keep rules for
TraceletStartupProviderin thetracelet_androidpackage to preventClassNotFoundExceptionon process start when aggressive shrinking (like R8 full mode) is used (#228). -
3.5.223 Jun 2026Release notes
Open source →FIX: Android continuous tracking no longer silently stops after a while on aggressive OEMs (Samsung One UI, etc.). The foreground-service wakelock used a fixed 10-minute auto-expiry and was never renewed, so once it lapsed the CPU could deep-sleep and FusedLocationProvider stopped delivering updates with no error or callback. The wakelock is now renewed for the lifetime of tracking (#222).
-
3.5.119 Jun 2026Release notes
Open source →FEAT: Crash detection now uses the device barometer as an extra confirmation clue — a serious crash or airbag deployment causes a quick cabin air-pressure change, which raises crash confidence on phones that have a pressure sensor. Phones without one simply skip this check, with no downside (#173). FEAT: Crashes are now corroborated by a sudden post-impact speed collapse — when the vehicle goes from fast to nearly stopped in the seconds right after the jolt, crash confidence is raised. It only ever adds confidence, never cancels a real crash (#181). FEAT: Falls are now corroborated by the classic free-fall → impact → stillness signature — a brief weightless drop followed by the body coming to rest raises fall confidence (#180). FEAT: Crash/fall confirmation is now process-death-safe — if the OS kills the app during the cancel countdown (phone thrown, vehicle at rest, Doze), the confirmed event is still delivered from a re-armed exact
AlarmManagerwake-up (#182). DOCS: Rewrote the Driving & Safety crash/fall confirmation section in plain, beginner-friendly language. -
3.5.019 Jun 2026Release notes
Open source →FEAT: Crash-detection ML model promoted from beta to stable — the shipped model is trained on the CC0 / public-domain Smartphone IMU Road Accident Detection dataset, so it is cleared for commercial use in production apps (#183). FEAT: The on-device encrypted model cache now auto-re-downloads when a new model version is published (SHA-256 of the cached blob no longer matches the expected digest), so model upgrades roll out in the same session instead of falling back to the rule engine for a cycle. FEAT (example): Driving & Safety page now shows a live crash-model download/load status indicator, a "Crash (ML model)" debug inference path, a "Benign bump" demo, and a bench "Throw-test" mode. PERF: Per-window crash-model probability is now logged for on-device observability.
-
3.4.218 Jun 2026Release notes
Open source →- REFACTOR: reformat test files and sync body context for consistent code style. (5552f795)
Release notes
Open source →- FEAT: implement telematics deduplication with synced-state tracking and improved foreground service fault tolerance. (0581c6e7)
-
3.4.117 Jun 2026Release notes
Open source →- FEAT(geofence): cross-platform geofenceModeHighAccuracy via GeofenceConfig. (491d5b83)
-
3.4.017 Jun 2026Release notes
Open source →- FIX: a single location batch is uploaded exactly once — replacing/cancelling a previously-registered sync provider prevents duplicate
requestSyncBodycalls and duplicate uploads/DB rows (#204). - FIX:
getCurrentPositionfloors passive priority to balanced so an explicit one-shot always obtains a fix instead of failing withLOCATION_FAILURE; per-call extras merge with global extras (#201). - REFACTOR: extract issues 185 and 198, fix iOS config mapping. (1d088e0d)
- FIX: a single location batch is uploaded exactly once — replacing/cancelling a previously-registered sync provider prevents duplicate
-
3.3.416 Jun 2026 -
3.3.315 Jun 2026 -
3.3.215 Jun 2026Release notes
Open source →Release notes
Open source →-
FIX (Location data, Android/iOS): Several location-map fields surfaced as static/default values in the Dart layer because the native-map → platform-channel converters dropped or mis-keyed them (#175):
getCurrentPosition(extras:, desiredAccuracy:)were silently ignored on Android (never forwarded to the SDK) — now applied.battery.isChargingwas alwaysfalse— the converter readisCharginginstead of the native snake_caseis_charging.isMovingwas alwaysfalse— readisMovinginstead of nativeis_moving.
Converters now read the native keys (with camelCase fallback), and field-by-field regression tests over the converters were added on both platforms to prevent recurrence.
-
TUNE (Crash detection): Lowered the default
crashGThresholdfrom3.0 gto2.0 g. Validation against the large VZCrash field dataset showed the 3.0 g speed-gated rule missed ~48% of real crashes (median impact ~2.2 g) while the false-positive budget was small. Crash detection is opt-in with a cancel-countdown, so the default now favours recall — raise it if you see too many prompts. See #173. (Crash detection remains beta pending first-party field validation.)
-
-
3.3.114 Jun 2026Release notes
Open source →- FIX(crash): harden crash/fall detection (confirmation survival, threshold, debounce, sample rate). (0a17e804)
Release notes
Open source →- REFACTOR(logging): route all SDK logs through TraceletLogger (no raw Log/NSLog). (e42b676a)
-
3.3.014 Jun 2026Release notes
Open source →- FEAT (Battery, Android): Motion-gated wakelock — drop the OEM partial wakelock when stationary and re-assert it on movement, via
AndroidConfig.releaseWakelockWhenStationary(opt-in, default off; gated on the hardware significant-motion wake sensor) (#162). - FEAT (Driving & Safety): On-device driving-behavior telematics —
harsh_braking/harsh_acceleration/harsh_cornering/speedingviaTelematicsConfig+Tracelet.onDrivingEvent(opt-in, default off) (#163). - FEAT (Driving & Safety): On-device transport-mode classifier (still/walking/running/cycling/vehicle) fusing accelerometer + GPS via
ClassifierConfig+Tracelet.onModeChange(#164). - FEAT (Driving & Safety): Crash & fall detection with a cancel-countdown confirmation flow via
ImpactConfig+Tracelet.onImpactandTracelet.confirmImpact/Tracelet.cancelImpact(opt-in, default off) (#165). - All three features are default-off and side-channel — no change to existing tracking when disabled. See Driving & Safety.
- FEAT (Battery, Android): Motion-gated wakelock — drop the OEM partial wakelock when stationary and re-assert it on movement, via
-
3.2.1913 Jun 2026 -
3.2.1812 Jun 2026Release notes
Open source →- FIX (Native):
ready()/getState()now populateState.configwith the active configuration instead of leaving it permanentlynull(#147). - FEAT: Add
HttpConfig.syncIntervalfor interval-based sync — the documented repeating-timer cadence was missing from the Dart config and the Pigeon layer; the native interval timer now flushes the offline queue on this cadence (#149). - FIX (Native):
destroySyncedLocations()returns the real number of synced-and-pruned locations instead of a hardcoded0stub (#154). - FEAT: Expose the offline queue with
getPendingLocations()andgetPendingLocationCount()(#159). - FIX (Native): Honor the
useKalmanFilterconfig key so the Extended Kalman Filter is no longer silently disabled by a key mismatch (#148). - FIX (Native): Propagate the detected activity (walking / driving / still) into recorded locations — fixes a permanent
"activity": "unknown"(#155). - FIX (Native): Rebuild the native location processor when
ready()applies a new config, so settings such asdistanceFiltertake effect immediately instead of using stale defaults (#157). - FIX (Native):
getCount()honors time-bound queries instead of always returning the whole-database total (#152). - FIX: Guard the
AuditConfighash-algorithm mapping so configuringsha384/sha512no longer crashes with a fatalRangeErrorduringready()— unsupported variants fall back tosha256(#150). - FIX (Native): The HTTP sync payload now includes each point's motion state
is_moving(#151) and its triggerevent(location / motionchange / heartbeat / geofence) (#156) — both were previously omitted by the native sync record.
- FIX (Native):
-
3.2.1712 Jun 2026Release notes
Open source →- FIX (Native): Resolve iOS auto-sync thread starvation by offloading synchronous HTTP requests to a background DispatchQueue to prevent blocking Swift Concurrency pools (#146).
- CHORE (Docs): Fix Nextra changelog rendering bug and improve auto-translation glossary script for internationalization.
-
3.2.1612 Jun 2026Release notes
Open source →- FIX (Native): Resolve Android/iOS getting stuck in the moving state and never transitioning back to stationary, which kept continuous GPS active and drained the battery. The accelerometer stillness sampler now stays active during the stop-timeout countdown and requires sustained motion — rather than a single noisy or stale sample — to abort it (#142).
- FIX (Native): Background and post-reboot location captures are persisted (and therefore synced) again. Headless tracking (killed-state relaunch / boot) never calls
ready(), so an internal readiness guard silently dropped every captured location before it reached the database, leaving auto-sync with nothing to upload. - FIX (Android): The foreground-service notification now reliably appears when the app is backgrounded or terminated with
showNotificationOnPauseOnlyenabled. The app's own foreground service skewed foreground/background detection (and OS process-importance updates lag), so the pause-only notification was suppressed even though tracking and syncing continued.
-
3.2.1511 Jun 2026Release notes
Open source →- FIX (Native): Allow
getState()andstop()to be called beforeready()is invoked, correctly reporting persistent state and shutting down background services if the app was restarted from a killed state. - CHORE: Update dependencies and constraints.
- FIX: Resolve
MissingPluginExceptionand test timing issues withsetHasCustomSyncBodyBuilder.
- FIX (Native): Allow
-
3.2.1411 Jun 2026Release notes
Open source →- FIX(sync): keep method channel alive to avoid iOS timeout bugs when no builder is registered. (9a083478)
- FIX(sync): resolve issue 134 where custom sync body timeouts prevented background syncs. (7fa16fdf)
- FIX(sync): fix background auto-sync abortion when no custom builder is registered (Issue #134). (631542a1)
- DOCS: add official documentation URL to all package READMEs. (9eb6951e)
- DOCS: integrate nextra website and update pubspec URLs. (99b7fda8)
Release notes
Open source →- FIX(sync): fix background auto-sync abortion when no custom builder is registered (Issue #134). (631542a1)
- FIX(android): prevent headless engine from overwriting sync interceptor (Issue 136). (b166bcd5)
- FIX(android): align deltaCoordinatePrecision default with Dart (Issue #137). (5edb9910)
- DOCS(android): document Issue 136 fix to prevent regression. (36b4b9c9)
- DOCS: add official documentation URL to all package READMEs. (9eb6951e)
- DOCS: integrate nextra website and update pubspec URLs. (99b7fda8)
-
3.2.1310 Jun 2026Release notes
Open source →- FIX(android):
startOnBootnow resumes tracking after a reboot even when the OS refuses to start the location foreground service fromBOOT_COMPLETED(Android 14 disallows starting alocation-type foreground service from boot). Previously the boot start was deferred until the app was next opened, so tracking silently never resumed after a reboot —BootReceivernow falls back to background WorkManager/alarm tracking when the foreground-service start is blocked. - FIX(android): HTTP sync now works headlessly after a reboot. A new process-start
ContentProviderwires the headless Dart bridge (TraceletSdk.dartSyncInterceptor+TraceletBootstrap.headlessDispatcherFactory) so background sync can refresh the auth token and build a custom sync body via the registered headless callbacks — previously these were only wired when a UI Flutter engine attached, so after a reboot sync POSTed with a stale token (or the wrong payload) until the app was opened.
- FIX(android):
-
3.2.1210 Jun 2026Release notes
Open source →- CHORE: Re-release to align the full federated package set and native SDKs to a single consistent version. The 3.2.11 release published with mismatched versions across some packages (a few resolved to 3.2.10). No functional code changes.
-
3.2.1109 Jun 2026Release notes
Open source →- FIX(android): Fall back to the headless engine when a custom sync-body round-trip times out, instead of aborting the sync. Fixes location sync stopping after a few minutes while the app is backgrounded (Issue #134).