Skip to content

Migrating from Transistorsoft

BGeo’s Dart API is intentionally shaped like Transistorsoft’s commercial background-geolocation SDK family — the same method names, event names, and config-key vocabulary Transistorsoft uses across its React Native, Cordova, and native bindings carries over to bgeo_background_geolocation almost unchanged, so most integrations move over with small changes. This page inventories what maps directly, what differs, and what BGeo deliberately does not implement. It’s factual, not a comparison or a claim of equivalence — BGeo is a compatible engine, not a clone.

Install swap

Only the dependency changes. Method names, the facade shape, and the location object stay the same.

  1. Remove your existing Transistorsoft plugin dependency from pubspec.yaml and add BGeo:

    Terminal window
    flutter pub remove <your_old_transistorsoft_dependency>
    flutter pub add bgeo_background_geolocation
  2. Update every import to the new package, using the hide State/as bg convention (the SDK’s own State snapshot type collides with Flutter’s State<T> widget-state class otherwise):

    import 'package:bgeo_background_geolocation/bgeo_background_geolocation.dart' as bg;
  3. Follow Installation for the Android Maven repo and iOS deployment target — these replace whatever native setup your previous plugin required. Check Compatibility first: BGeo requires Android minSdk 24, iOS 15.5+, and a reasonably current Flutter/Dart SDK (null-safety, Future/Stream-based API) — there is no Flutter web or desktop support, since the tracking engine is mobile-only.

The license key moves, the mechanism doesn’t

Both SDKs read the license from the native manifest at launch — before any Dart runs — so the shape of this step is familiar, and it’s identical regardless of which language binding sits on top, since the check happens entirely at the native layer. Only the key names change, and BGeo verifies its key offline (no license call home):

android/app/src/main/AndroidManifest.xml
<application>
<!-- Before (Transistorsoft) -->
<meta-data
android:name="com.transistorsoft.locationmanager.license"
android:value="YOUR_TRANSISTOR_LICENSE" />
<!-- After (BGeo) -->
<meta-data
android:name="com.bgeo.license"
android:value="BGEO1....YOUR_KEY" />
</application>
ios/Runner/Info.plist
<!-- Before (Transistorsoft) -->
<key>TSLocationManagerLicense</key>
<string>YOUR_TRANSISTOR_LICENSE</string>
<!-- After (BGeo) -->
<key>BGeoLicense</key>
<string>BGEO1....YOUR_KEY</string>

See License keys for the full snippets, evaluation-build rules, and error codes.

Config and method compatibility

Most Transistor config keys and methods behave identically — see the Config reference and Methods reference for exact Dart types and defaults. What maps directly (unchanged names and shapes, adapted only to Dart’s Future/named-constructor idiom):

  • Lifecycle: ready, setConfig, start, stop, getState, changePace
  • Positioning: getCurrentPosition, watchPosition, stopWatchPosition
  • Events: onLocation, onMotionChange, onHeartbeat, onProviderChange, onHttp, onConnectivityChange, onGeofence, onGeofencesChange — each returns a StreamSubscription in this Dart binding rather than a plain unsubscribe function
  • Permissions: requestPermission, getProviderState, requestTemporaryFullAccuracy, isPowerSaveMode/onPowerSaveChange
  • Odometer: getOdometer, setOdometer, resetOdometer
  • Upload queue: sync, getLocations, destroyLocations, getCount, destroyLocation, insertLocation
  • Geofences: addGeofence, addGeofences, removeGeofence, removeGeofences, getGeofences, geofenceExists — see the Geofencing guide
  • Logging: logger.error/warn/info/debug/verbose, getLog, destroyLog, uploadLog — see the Logging & debugging guide
  • HTTP config: url, method, headers, params, extras, httpRootProperty, autoSync, autoSyncThreshold, disableAutoSyncOnCellular, batchSync, maxBatchSize, maxRecordsToPersist
  • Motion/filter config: distanceFilter, stopTimeout, stationaryRadius, heartbeatInterval, desiredAccuracy, locationFilterPolicy, kalmanProfile
  • authorization (JWT refresh, now a typed Authorization object) — see the HTTP guide’s authorization section
  • The notification sub-keys (title, text, channelId, channelName, smallIcon, color, priority), now a typed Notification object

The location object shape is unchanged (coords, timestamp, isMoving, activity, battery, odometer, uuid, extras) — see Data types. Field names are camelCase Dart getters over the same snake_case wire payload (is_moving on the wire, isMoving on Location), a bridge-level convenience the JS binding doesn’t need to make since JS already uses whichever casing the wire sends.

A handful of keys are accepted for API compatibility but currently do nothing. Don’t rely on foregroundService or backgroundPermissionRationale, and note that debug only plays sound cues — see Limitations — accepted-but-no-op config keys before you build around any of them.

API parity: what’s not here

BGeo deliberately does not implement the following part of Transistorsoft’s surface — an SDK-level scoping decision independent of which language binding sits on top, so it applies here exactly as it does on any other BGeo binding:

Transistor API / configAlternative in BGeo
schedule / startSchedule / scheduleUseAlarmManagerRun your own scheduler (a Dart Timer, or a native alarm) that calls start()/stop().
locationTemplate / geofenceTemplateShape the upload body with httpRootProperty/params/extras instead of a template string — see Shaping the body.
transistorAuthorizationTokenN/A (Transistorsoft-account specific) — use authorization for your own backend.
Custom notification layout / actions / stringsThe supported Notification fields (title/text/channelId/channelName/smallIcon/color/priority) cover a fixed layout, not custom actions or arbitrary strings.
emailLoguploadLog() to your own logUrl endpoint instead of emailing a log file.
useSignificantChangesOnlyNo equivalent mode — the engine manages its own wake sources; see Tracking lifecycle — wake sources.
stopOnStationary / stopAfterElapsedMinutesCall stop() yourself from onMotionChange/onHeartbeat.
persistModeN/A — all tracked locations persist by default; a one-shot getCurrentPosition() fix opts in via its persist option instead.
timestampFormatN/A — timestamps are always ISO-8601 UTC strings, see Location.timestamp.
locationsOrderDirectionN/A — the persisted queue is always oldest-first, see Data pipeline — persistence.
Burst averaging (rollingWindow/burstWindow/maxBurstDistance), an onLocationFilter-style callback, kalmanDebug/filterDebugUnbuilt — these are unknown keys, silently stored but ignored by the native config dict. The implemented filter surface is locationFilterPolicy, kalmanProfile, and odometerAccuracyThreshold — use those instead of per-fix burst averaging or a filter-decision callback.
reset()Call setConfig() with the values you want restored — see the Config reference for the documented default of each key.
startGeofences() (geofence-only tracking mode)start() already runs geofences alongside location tracking — there’s no separate mode.
getLocations() pagination / SQLQuerygetLocations() returns the full queue, oldest-first, as a List<Location>; filter or paginate it in Dart. Note a large offline queue means a large payload crossing the platform channel in one call — a generic method-channel cost, not specific to this method.
startBackgroundTask() / stopBackgroundTask()N/A.
getDeviceInfo() / getSensors()N/A.

Behavioral differences worth knowing

  • No legacy failure-callback quirk. Some Transistorsoft bindings carry a quirk where supplying a failure callback makes ready()/start()/etc. resolve instead of reject/throw on an error. This Dart API was built Future-first from the start and has no callback parameters at all — a failed ready()/start()/stop() call always completes its Future with an error (typically a PlatformException), full stop. There’s nothing to migrate here beyond removing any old failure-callback handling.
  • sync() semantics are unchanged. It resolves with a List<Location> snapshot of the queue taken before the drain starts, not what remains afterward. See sync().
  • Headless dispatch is Android-only. registerHeadlessTask() runs your task in a background Flutter engine for seven event types (heartbeat, motionchange, geofence, providerchange, powersavechange, http, connectivitychangelocation is excluded). The event arrives as HeadlessEvent(name, params), with every payload field other than name nested under params. Your task must be a top-level function or static method — Dart’s callback-handle mechanism can’t resolve a closure in a fresh isolate. iOS has no headless equivalent — see Boot & killed-app behavior: iOS: no headless.
  • iOS relaunch model differs internally, same external guarantee. BGeo keeps tracking alive across kill/reboot with a session-based engine (CLLocationUpdate.liveUpdates/CLBackgroundActivitySession, on by default on iOS 17+) plus significant-location-change monitoring and a rolling wake region, rather than Transistorsoft’s own implementation — see Boot & killed-app behavior for the full model.

Steps

  1. Install bgeo_background_geolocation; remove your old Transistorsoft dependency. Set up the Android Maven repo + iOS deployment target.
  2. Point every import at package:bgeo_background_geolocation/bgeo_background_geolocation.dart.
  3. Replace the Transistorsoft license entries in AndroidManifest.xml and Info.plist with BGeo’s — see License keys.
  4. Move JWT/token-refresh settings into an Authorization object.
  5. Remove any usage of the keys/methods listed under API parity, and check Limitations for accepted-but-no-op keys.
  6. Test on a real device — background, kill/relaunch, reboot — see Boot & killed-app behavior.