Skip to content

Migrating from Transistorsoft

BGeo’s API is intentionally shaped like Transistorsoft’s commercial tslocationmanager: the same method names, the same config keys, the same event vocabulary. A migration is mostly a dependency swap, not a redesign.

This guide describes the shape of the move rather than a specific version’s exact imports — substitute whatever your current dependency and package names are.

1. Swap the dependency

app/build.gradle.kts
dependencies {
// Before
// implementation("com.transistorsoft:tslocationmanager:+")
// After
implementation("dev.bgeo:background-geolocation:0.3.0")
}

Transistorsoft ships from its own Maven repository, so you can usually delete that maven { url = ... } block from settings.gradle.kts as well — BGeo is on Maven Central.

2. Move initialisation into Application.onCreate

This is the one structural change worth doing carefully:

MyApplication.kt
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
BackgroundGeolocation.attach(this)
}
}

attach() wires the engine to the process for the process’s whole lifetime, which is what lets a system-restarted process (boot, geofence, service) deliver events to your listeners without any headless registration.

3. Drop the licence key

BGeo is free and needs no license key. Delete the com.transistorsoft.locationmanager.license <meta-data> from AndroidManifest.xml and add nothing in its place.

4. Adapt to coroutines

Transistorsoft’s Android API is callback- and Future-based; BGeo’s is suspend functions and Flows:

// Before, roughly
BackgroundGeolocation.ready(config) { state -> if (!state.enabled) BackgroundGeolocation.start() }
// After
lifecycleScope.launch {
val state = BackgroundGeolocation.ready(config)
if (!state.enabled) BackgroundGeolocation.start()
}

Every event also has a callback form (onLocation { } returning a Subscription) if you would rather not restructure call sites at once — see Events.

Config and method compatibility

Most Transistor config keys and methods behave identically — see the Config reference and Methods reference for exact Kotlin types and defaults. What maps directly (unchanged names and shapes, adapted only to the coroutine idiom):

  • Lifecycle: ready, setConfig, start, stop, getState, changePace
  • Positioning: getCurrentPosition, watchPosition, stopWatchPosition
  • Events: onLocation, onMotionChange, onHeartbeat, onProviderChange, onHttp, onConnectivityChange, onGeofence, onGeofencesChange — each returns a Subscription, and each also exists as a Flow
  • Permissions: requestPermission, getProviderState, 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 AuthorizationConfig) — see the HTTP guide’s authorization section
  • The notification sub-keys (title, text, channelId, channelName, smallIcon, color, priority), now a typed NotificationConfig

The location object shape is unchanged (coords, timestamp, isMoving, activity, battery, odometer, uuid, extras) — see Data types. Field names are camelCase Kotlin properties over the same snake_case wire payload (is_moving on the wire, isMoving on Location), a decoding convenience the raw payload 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 (WorkManager, or an AlarmManager 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 yourself. A large offline queue decodes in one go, so read it off the main thread.
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() resolve instead of failing. This API has no callback parameters at all: a failed call throws a BGeoException, full stop. There is nothing to migrate beyond deleting old failure handlers.
  • sync() semantics are unchanged. It returns a List<Location> snapshot of the queue taken before the drain starts, not what remains afterwards. See sync().
  • No headless registration. Transistorsoft’s Android binding for React Native and Flutter needs a headless task because their runtimes die with the app. A native app does not: Android restarts your process and calls Application.onCreate, so attach() there is the whole mechanism. Delete the headless plumbing rather than porting it — see Boot & killed-app behaviour.
  • The engine is not the same engine. BGeo’s tracking, filtering and upload are its own implementation with its own defaults; a config that was tuned against Transistorsoft’s behaviour is a starting point, not a guarantee of identical output. Re-check distanceFilter, stopTimeout and stationaryRadius against a real drive before shipping.

Steps

  1. Swap the dependency to dev.bgeo:background-geolocation; drop the Transistorsoft Maven repository from settings.gradle.kts.
  2. Move initialisation into Application.onCreate and call attach() there.
  3. Delete the Transistorsoft licence <meta-data> from AndroidManifest.xml — BGeo needs no key.
  4. Re-point imports at com.bgeo.sdk; add imports for the extension functions (geofences, queue, logger).
  5. Wrap ready()/start()/stop() call sites in a coroutine, or keep the callback forms for events while you migrate.
  6. Delete headless-task registration.
  7. Drive the route you care about and compare point density before deleting the old integration.