Quick start
This gets a device recording a fix every 30 seconds while moving and every 3 minutes while parked, and uploading to your endpoint once a minute.
The code
Section titled “The code”import LongPing from 'react-native-long-ping';
// On every app launch (safe to repeat: never starts, stops or prompts).export async function setUpTracking(token: string) { await LongPing.configure({ movingIntervalSec: 30, parkedIntervalSec: 180, http: { url: 'https://api.example.com/locations', batch: true, uploadIntervalSec: 60, }, notification: { title: 'On duty', text: 'Sharing your location with dispatch' }, });
await LongPing.setAuthorization({ accessToken: token });}
// When the driver goes on duty.export async function goOnDuty() { // Your own rationale screen first, then: await LongPing.requestPermission('always'); await LongPing.start();}
// When the driver goes off duty.export async function goOffDuty() { await LongPing.stop(); // queued records still upload}And somewhere in your UI, if you want to show what is happening:
useEffect(() => { const subs = [ LongPing.onLocation((location) => console.log('fix', location.timestamp, location.coords)), LongPing.onMotionChange(({ isMoving }) => console.log(isMoving ? 'moving' : 'parked')), LongPing.onHttp(({ status, count }) => console.log('upload', status, count)), ]; return () => subs.forEach((s) => s.remove());}, []);What happens
Section titled “What happens”-
configure()replaces the whole config with the defaults plus what you pass, validates it, saves it on the device and applies it. It never starts, stops or prompts, so call it on every launch. A bad value rejects withINVALID_CONFIGand the key in the message. -
setAuthorization()stores your access token in the Keychain (iOS) or an Android Keystore-backed store. Every upload carriesAuthorization: Bearer <token>. See Authentication & token refresh for refresh tokens. -
requestPermission('always')shows the OS permission flow. It is the only call that ever shows a dialog. See Permissions. -
start()checks permission and location services, savesenabled = true, and records an immediatemotionchangefix in the moving state. From then on a fix is recorded everymovingIntervalSec(30 s). After 5 minutes inside a 75 m radius (stopTimeoutSec,stopRadiusM) it switches to parked and records everyparkedIntervalSec(180 s). Callingstart()when tracking is already on is safe. -
Uploads go to
http.urlat most once everyuploadIntervalSec(60 s), as{"locations": [ … ]}. Any 2xx reply deletes the sent records from the on-device queue.
See it on your server
Section titled “See it on your server”The smallest possible receiver, to watch the first batch arrive:
import { createServer } from 'node:http';
createServer((req, res) => { let body = ''; req.on('data', (chunk) => (body += chunk)); req.on('end', () => { const { locations = [] } = JSON.parse(body || '{}'); for (const l of locations) console.log(l.timestamp, l.event, l.coords.latitude, l.coords.longitude); res.writeHead(200, { 'content-type': 'application/json' }).end('{}'); });}).listen(8787);For real servers (deduplication, auth, replies) see Receiving uploads on your server.
- Tune the clock with the calculator in Choosing intervals & battery.
- Read every option in the Config reference.
- Before rolling out on Android, read Android battery managers.