locus 2.1.1
locus: ^2.1.1 copied to clipboard
Core background geolocation SDK of the WeOrbis ecosystem for Flutter. Native tracking, geofencing, activity recognition, and sync.
Changelog #
All notable changes to this project will be documented in this file.
2.1.1 - 2026-02-18 #
Fixed #
- Android/iOS: Multi-engine singleton guard — Added singleton pattern to prevent secondary Flutter engines (created by
flutter_background_service,geolocator, etc.) from initializing duplicate native resources. Previously, when a background service engine was destroyed, itsLocusPlugin.onDetachedFromEngine()would tear down shared native resources (Activity Recognition PendingIntents, connectivity listeners, database connections), killing the primary engine's active tracking. Secondary engines now skip native resource initialization and cleanup entirely.
2.1.0 - 2026-02-17 #
Fixed #
- Android: ForegroundService crash on Android 14+ — Restructured to two-phase notification strategy, calling
startForeground()immediately with a minimal notification before building the full one. EliminatesForegroundServiceDidNotStartInTimeException. (#22) - Android: Odometer float precision loss — Switched from 32-bit float to 64-bit long storage using
Double.toBits()/fromBits()with automatic migration from legacy format. - Android: TrackingStats race condition — Added
@SynchronizedtoonLocationUpdate()andonTrackingStop()to prevent concurrent session field corruption. - Android: EventDispatcher race on eventSink — Use captured local reference in
mainHandler.postblock to prevent null dereference if sink is cleared between check and use. - Android: SyncManager log exposure — Sanitized error messages in
Log.e()calls to strip URLs that may contain tokens or sensitive path segments. - Android: MotionManager null safety — Replaced
!!assertions with safe?.letpattern onmotionTriggerRunnableandstopTimeoutRunnable. - Android: SystemMonitor null activeNetwork — Added null check on
ConnectivityManager.activeNetworkwith early return. - Android: LocationEventProcessor privacy log — Removed privacy mode config value from log output.
- Android: TrackingStats integer overflow — Explicit
Longdivision for tracking minutes calculation. - Android: HeartbeatScheduler first beat — Fire first heartbeat immediately instead of waiting one full interval.
- Android: ForegroundService null actions — Added
.filterNotNull()on notification actions array. - Android: SQLite storage integrity — Wrapped operations in transactions,
onUpgradeno longer drops tables. - Android: HeadlessService SharedPreferences — Aligned prefs name and key with ConfigManager.
- Dart: RoutePoint unsafe cast — Safe null-aware cast with fallback for
latitude/longitude. - Dart: TripSummary unsafe DateTime.parse — Use
DateTime.tryParse()with fallback instead of throwing on malformed dates. - Dart: Location silent fallback — Added debug-mode logging when coords fall back to (0,0) due to validation failure.
- Dart: Adaptive heartbeat — Stationary heartbeat now factors battery level instead of always using max interval.
- Dart: Headless sync body builder — Fixed callback to construct proper
SyncBodyContextmatching the typed contract instead of passing a raw Map. - iOS: SyncManager thread safety — Thread-safe network state and URLSession lifecycle improvements.
- iOS: SQLiteStorage memory safety — All
sqlite3_bind_textcalls now useSQLITE_TRANSIENTto prevent use-after-free. - iOS: SQLiteStorage concurrency —
createTablesmoved inside queue.sync block.
Changed #
- Adaptive tracking — Stationary heartbeat uses averaged interval for normal battery level (previously always used max).
- Event processing — Spoof detection, privacy zone filtering, and polygon geofence detection now apply to heartbeat, motionChange, and schedule events (previously location-only).
- AppLifecycleState.inactive — Now treated as foreground to avoid unnecessary background transitions during permission dialogs and phone calls.
- Config validation —
maxMonitoredGeofences > 20now produces a warning instead of an error for iOS compatibility. - Debug overlay tests — Fixed
ink_sparkle.fragshader issue in test environment usingNoSplashtheme.
Added #
- SSL pinning configuration options (
sslPinningCertificate,sslPinningFingerprints). LocusSync.isSyncReady()method.- Config URL format validation warnings.
- iOS log level
"off"support.
2.0.1 - 2026-01-12 #
Changed #
- Transfer of Ownership: Project ownership officially transferred to the WeOrbis ecosystem.
- License Change: Relicensed from PolyForm Small Business License to MIT License for better community adoption and accessibility.
- Repository URLs: Updated all repository links to point to the new location at
github.com/weorbis/locus. - Branding & Contact: Updated contact emails to
info@weorbis.comandsecurity@weorbis.com. Removed all personal developer references to reflect organizational ownership.
2.0.0 - 2026-01-07 #
Breaking #
- Removed v1.x facade methods: All deprecated static methods were removed. Use the service-based API via
Locus.location,Locus.geofencing,Locus.privacy,Locus.trips,Locus.dataSync, andLocus.battery. Core lifecycle methods (ready,start,stop,getState) remain onLocus. - Removed features:
emailLog()andplaySound()have been removed. - url_launcher removed:
DeviceOptimizationService.showManufacturerInstructions()replaced withgetManufacturerInstructionsUrl()returning a URL string. Apps should handle URL launching themselves.
Added #
- v2.0 Service-Based API: New domain-organized services accessible via static properties:
Locus.location- Location tracking, streaming, and queriesLocus.geofencing- Geofence CRUD, monitoring, and workflowsLocus.privacy- Privacy zone managementLocus.trips- Trip tracking and stateLocus.dataSync- HTTP sync, queue management, and policiesLocus.battery- Power state, adaptive tracking, and benchmarking
- Migration CLI Tool:
dart run locus:migratecommand for automated v1.x → v2.0 migration- Pattern-based detection of deprecated API usage
- Dry-run mode for safe preview
- Detailed migration suggestions with line numbers
- Monorepo support: Automatically detects and processes multiple packages in monorepo workspaces
- Discovers all Dart/Flutter packages in the workspace structure (supports
packages/,apps/,modules/, etc.) - Pre-flight Locus SDK usage detection per package
- Aggregates analysis results across all packages with per-package breakdown
- Applies migrations to each package independently
- Single backup for entire monorepo
- Distinguishes between Flutter apps and packages in output
- Discovers all Dart/Flutter packages in the workspace structure (supports
- Rollback support:
--rollbackflag to restore from most recent backup - Analysis-only mode:
--analyze-onlyto scan without migration suggestions - Pattern filtering:
--ignore-patternand--only-categoryoptions for targeted migrations - Migration hints: Smart suggestions for headless callbacks, config changes, and removed features
- 70+ migration patterns: Comprehensive coverage across all service categories
- Location, Geofencing, Privacy, Trips, Sync, Battery, Diagnostics
- Config parameter renames (url→syncUrl, httpTimeout→syncTimeout)
- Removed feature detection with TODO comments
- Headless callback pragma annotation hints
- Service behavior tests: Expanded unit coverage for the new v2.0 service APIs
- Full suite now green (666 tests passing)
- Dynamic headers support:
setDynamicHeaders()now works on both Android and iOS - Sync policy support (iOS):
setSyncPolicy()handler added for iOS platform parity - Metered connection detection (iOS):
isMeteredConnection()handler for WiFi-only sync - Tracking data cleanup helper:
Locus.clearTrackingData()for clearing stored locations and (optionally) the sync queue without stopping tracking
Fixed #
- Android: Fixed Kotlin stdlib version mismatch (was 1.9.22, now uses plugin's 2.1.0)
- Android:
setSyncPolicy()now applies to ConfigManager immediately instead of being a no-op - Android: Bulk
addGeofences()now respects per-geofencenotifyOnEntry/notifyOnDwellflags - Android:
motionManagerproperly stopped on plugin detach (prevents PendingIntent leak) - Android: ConfigManager properties marked
@Volatilefor thread safety - Android: BackgroundTaskManager uses
ConcurrentHashMapfor thread-safe task tracking - Android: SyncManager graceful shutdown with
isReleasedflag to prevent callbacks after release - Android: Database helpers (LocationStore, QueueStore) explicitly closed on detach
- iOS:
sendEventdispatched on main thread to prevent crashes from background delegates - iOS:
isSyncPausedmade thread-safe with serial dispatch queue - iOS: GeofenceManager cleanup added to stop monitoring and clear delegate on deinit
- iOS: Heartbeat timer properly invalidated when plugin deallocates
- Build: Removed hardcoded JDK path from gradle.properties
- Build: Removed unused
xmldependency from pubspec.yaml - Build: Added CoreLocation framework to iOS podspec
Changed #
- MockLocus enhancements: Added
emitPowerSaveChange(),emitPowerStateChange(), and method call tracking for sync/battery APIs - Lint rules: Added comprehensive lint rules (prefer_const_constructors, prefer_final_fields, unawaited_futures, cancel_subscriptions, close_sinks, etc.)
1.2.0 - 2026-01-03 #
Breaking #
- Internal imports were reorganized into feature-first barrels. Any direct imports under
package:locus/src/core/...,package:locus/src/services/..., orpackage:locus/src/models/...from 1.1.x will break. Migrate to the public barrels exposed by lib/locus.dart or, for advanced/internal use, the consolidated lib/src/models.dart and lib/src/services.dart.
Added #
- Polygon Geofences: Define complex boundaries with arbitrary shapes using
PolygonGeofence. Supports enter/exit detection with efficient ray-casting algorithm. - Privacy Zones: New privacy protection feature allowing users to exclude, obfuscate, or reduce accuracy in sensitive areas.
- Trip Tracking: Automatic trip detection with start/end events, route recording, and trip summaries.
- Geofence Workflows: Multi-step geofence sequences with timeouts for complex location-based flows.
- Tracking Profiles: Pre-defined and custom tracking profiles with automatic switching rules.
- Battery Runway: Estimate remaining tracking time based on current battery drain rate.
Changed #
- Architecture: Restructured codebase to feature-first organization (MVVM pattern). Code is now organized by domain (location, geofencing, battery, etc.) rather than by layer (models, services).
- Import Paths: Barrel exports simplified. Use
import 'package:locus/locus.dart'for all public APIs.
Fixed #
- Android: guarded foreground service startup for null intents/notification permission errors and prevented stale geofence payloads from persisting when privacy mode is enabled; geofence restore now clears persisted entries on Play Services failures to keep Dart and native in sync.
- Android: cleaned up cached headless Flutter engines after idle to avoid leaks.
- iOS: startTracking now requests/validates permission before enabling, and significant-change monitoring runs only with Always authorization.
- Dart: start returns disabled state when native start fails instead of assuming enabled; destroy now also invokes native stop/cleanup hooks.
- Dart: location queries honor limit/offset without loading unbounded history; trip engine awaits persistence to avoid dropped saves; enqueue now surfaces native failures instead of returning empty ids.
1.1.0 - 2026-01-01 #
Added #
- Testability: Refactored
Locusto support mocking viasetMockInstance(), enabling robust unit testing for apps using the SDK. - Structured Logging: Replaced flat-file logging with SQLite-based structured logs on Android and iOS. Added
Locus.getLog()returningList<LogEntry>. - Authentication Handling: Implemented smart 401 Unauthorized handling. Sync pauses automatically on 401; use
Locus.resumeSync()after token refresh. - Permissions Workflow: Added
PermissionAssistantto manage complex permission sequences (Location, Activity, Notification) with UI callbacks. - Device Optimization: Added
DeviceOptimizationServiceto detect OEM battery restrictions and guide users to "Don't Kill My App" instructions (Android). - Configuration Presets: Added
Config.fitness()andConfig.passive()factory constructors for quick setup. - iOS Data Persistence: New
SQLiteStorageengine for iOS, providing high-performance persistent storage (replacingUserDefaults). - Custom Sync Body Builder: Added
Locus.setSyncBodyBuilder()to allow full control over HTTP request body structure. Ideal for backends requiring custom JSON envelopes (e.g.,{ ownerId, taskId, polygons: [...] }). - Headless Sync Body Builder: Added
Locus.registerHeadlessSyncBodyBuilder()for background sync with custom body formats, even when the app is terminated. - Native Sync Envelope Support: The
extrasconfig field is now merged at the top level of HTTP sync bodies on both Android and iOS. Combined withhttpRootProperty, this enables custom JSON structures without Dart callbacks. - Developer Experience (DX) Improvements:
- Added
locus_errors.dartwith descriptive exception types (NotInitializedException,SyncUrlNotConfiguredException,HeadlessRegistrationException, etc.). - Headless registration now prints detailed instructions when callback handles fail.
- Native sync adds debug logs explaining why sync was skipped (no URL, paused, etc.).
- Config validator now warns about common issues:
extraswithouthttpRootProperty,autoSyncwithoutbatchSync,enableHeadlesswithoutstopOnTerminate: false.
- Added
- Centralized
LocusConstantsfor all SDK parameters. - Proper
toString()implementations for core models.
Fixed #
- iOS Storage: Migrated storage to SQLite to resolve data truncation issues.
- Platform Parity: Implemented confidence threshold filtering for motion activity on iOS.
- Error Handling: Standardized error responses across platforms.
- Lifecycle Management: Fixed iOS
SyncManagerlifecycle issues. - Test Stability: Resolved unit and integration test flakiness.
Changed #
- Refactored
StorageManagerto utilize the new SQLite backend. - Simplified internal method channel handlers.
- Updated native battery stats to include detailed drain estimates.