Skip to content

Example app

The SDK’s source repo ships a full example app under example/ — a dev/debug tool, not a template to copy into your project. It depends on the SDK the same way a real consuming app would: a file:.. dependency in its package.json, symlinked into node_modules and watched by Metro, so editing SDK source hot-reloads into the example instead of requiring a publish step. Screenshots throughout these docs are taken from it.

Running it

Terminal window
npm install
# Android
npm run android
# iOS
cd ios && pod install && cd ..
npm run ios

android/local.properties (the sdk.dir entry) isn’t committed to git — create it locally, pointing at your Android SDK, before the first Android build.

Both npm run android and npm run ios build debug binaries. No account or key is needed, and the app talks to no server of ours: everything it records — track, logs, geofences — stays on the device.

Tour of the screens

The app is a three-tab bottom navigator: Map, Logs, Settings.

Map

The live map: a status chip (tracking/stopped, moving/stationary, battery level, point count), Start/Stop tracking, and a getCurrentPosition() button. The map itself draws the tracked route as a polyline, with Follow, Pts (point markers), Line, and Geo (geofence) layer toggles, plus a From/To range picker that swaps the live track for the locally recorded history in that time range. Long-pressing anywhere on the map opens the geofence-creation form pre-filled with the tapped coordinates; tapping an existing geofence’s pin opens the same form for editing or deletion. Geofence ENTER/EXIT/DWELL events appear as their own markers on the route, colored distinctly from ordinary location points.

The example app's Map screen on iOS and Android: the status chip (stationary, battery, point count), Start/Stop and Get position buttons, the tracked route drawn as a polyline, and the collapsed Collected coordinates sheet.

See the geofencing guide for the creation form’s fields and what a registered geofence looks like on this map.

Logs

A live event console (timestamp, [LEVEL], event tag, message, data). It merges two sources: your own JS-side log lines (streamed live as the app logs them) and the native engine’s own persisted rows (motion.*, wake.*, track.*, and more), polled from getLog() every few seconds. A level filter (all/verbose/debug/info/warn/error), a follow-tail toggle, and a clear button round it out. See the logging guide for what ends up in this stream and how it’s retained.

Settings

Every working Config key, grouped into sections (Geolocation, Motion/Activity, Power, HTTP/Sync, Persistence, Geofencing, Application, Diagnostics/Engine, Notification) — platform-only keys (like iOS’s session-engine toggle or Android’s notification channel fields) only show up on their platform. Changing a field calls setConfig() immediately and persists the override in AsyncStorage; on the next cold start, every persisted override is merged back over the app’s base config before ready() is called. That’s what makes this screen useful for experimentation: you can flip any tracking, filtering, or upload knob on a real device and see the effect immediately, without touching code or rebuilding — and a Reset config to defaults button clears every override back to the app’s baseline in one tap.

Below the config sections, an Engine state panel surfaces getState() fields, the upload queue size, and log history size, with buttons to force a sync() (uploads only when you have set your own url), destroy the queue, or reset the odometer.