@wayq/beekon-rn
v0.4.0
Published
React Native binding for the Beekon location SDK (Android + iOS).
Readme
Capture location in the foreground and background, keep a queryable history on the device, define geofences, and optionally upload to a backend you control. Nothing leaves the device unless you set a sync endpoint. The JavaScript API is fully typed.
Features
- Foreground and background tracking that survives app termination
- Battery-aware capture: time/distance filtering, accuracy presets, auto-pause while stationary
- On-device history you can query at any time
- Geofencing with enter and exit events, plus optional per-geofence local notifications that fire offline and even when the app is killed
- Optional batched server sync with automatic retry
- Diagnostic logging: query/export an on-device buffer, stream live entries
- Activity detection (walking, running, cycling, automotive)
- Built for the React Native New Architecture
Requirements
| | Minimum | |---|---| | React Native | 0.76 (New Architecture) | | iOS | 17.0 | | Android | 8.0 (API level 26) |
Install
npm install @wayq/beekon-rniOS — cd ios && pod install. Android — no extra steps; the module links automatically. See Setup for the OS config.
Quick start
import { Beekon } from '@wayq/beekon-rn';
const offState = Beekon.onState((state) => console.log('state:', state.kind));
const offLocation = Beekon.onLocation((loc) =>
console.log(loc.latitude, loc.longitude, loc.timestamp),
);
// Configure is optional. Request OS permissions before starting (see Setup).
await Beekon.configure({
mode: 'local',
tracking: {
minTimeBetweenLocationsSeconds: 30,
minDistanceBetweenLocationsMeters: 100,
},
});
await Beekon.start();start() and stop() never throw. Observe onState to learn whether tracking began and why it stopped ('user' | 'permissionDenied' | 'locationServicesDisabled' | 'locationUnavailable' | 'backgroundStartDenied' | 'system').
Send to your backend
Add a sync config and Beekon uploads fixes and geofence events to your backend — batched, retried, and removed from the device once your server accepts them. Without a sync config, all data stays on the device.
await Beekon.configure({
mode: 'custom',
sync: {
url: 'https://api.example.com/locations',
headers: { Authorization: 'Bearer <token>' },
// intervalSeconds defaults to 300, batchSize to 100
},
});
Beekon.setUserId('abc123'); // identifies the user — sent top-level on every upload
Beekon.setExtras({ plan: 'pro' }); // opaque custom fields attached to every upload
Beekon.onSyncStatus((status) => console.log('sync:', status.kind));Your server receives a small JSON envelope and acknowledges it with a status code. Build your ingest endpoint is a complete, working example. For rotating bearer tokens, set sync.auth and the SDK attaches and natively refreshes the token — proactively before expiry, reactively on a 401/403 — even in the background. See Auth & token refresh.
More
// History (stored on the device, survives restarts)
const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
const fixes = await Beekon.getLocations(since, new Date());
// Geofences — enter/exit events that keep firing across launches
await Beekon.addGeofences([
{ id: 'office', latitude: 37.331, longitude: -122.031, radiusMeters: 150 },
]);
const offGeofence = Beekon.onGeofenceEvent((e) => console.log(e.geofenceId, e.type));
// Per-geofence local notification — rendered natively at crossing time,
// offline and even when the app is killed. Add `notification` to a geofence:
await Beekon.addGeofences([
{
id: 'home',
latitude: 37.331,
longitude: -122.031,
radiusMeters: 150,
notification: {
delivery: 'local', // 'local' is the only implemented mode ('cloud' reserved)
onEnter: { title: 'Welcome home', body: 'You arrived', deepLink: 'myapp://home' },
onExit: { title: 'On the move', body: 'You left home', importance: 'default' },
},
},
]);
// One-shot fix, independent of tracking (null on timeout)
const fix = await Beekon.getCurrentLocation();
// Pre-start permission check (the app still owns the request)
const status = await Beekon.getPermissionStatus();
// Config-aware "permission doctor" — the OS permissions the CURRENT config
// needs, each marked `satisfied` against the live grant (never prompts).
// Call after configure(). Reports activity-recognition and, on Android,
// notifications — not just location.
const required = await Beekon.getRequiredPermissions();
for (const r of required) {
// r.permission, r.importance ('required' | 'recommended'), r.satisfied, r.rationale
if (!r.satisfied) console.log(`${r.permission} (${r.importance}): ${r.rationale}`);
}
// Explicit permission requests (native ≥ 0.4.0) — ask in context, one step per
// onboarding screen; the SDK performs each ask correctly for the platform
// (FINE+COARSE pairing, the Android 11+ background two-step, the iOS one-shot
// "Always" upgrade). Beekon never prompts on its own, and third-party
// permission libraries remain fully supported alongside.
const step = await Beekon.requestNextNeededPermission(); // null = nothing needed
if (step?.outcome === 'requiresSettings') await Beekon.openSettings('location');
// Diagnostics — runtime level, live tail, NDJSON export for bug reports
await Beekon.setLogLevel('debug');
const logPath = await Beekon.exportLog();License (optional)
A license key is optional and purely observational — an absent, expired, or invalid key never blocks, degrades, or delays tracking. Supply one and watch the status:
// App- and product-bound, so it's safe to commit to source control.
await Beekon.configure({ mode: 'local', licenseKey: 'eyJ…' });
// One-shot, or subscribe with Beekon.onLicenseStatus((s) => …) for live changes.
const status = await Beekon.licenseStatus();
// status.status: 'notDetermined' | 'licensed' | 'evaluation' | 'expired'
// | 'updateEntitlementLapsed' | 'invalid'
// when 'licensed': { tier, entitlements }; when 'invalid': { reason }Without a key, Beekon runs in evaluation mode — fully functional. Details: docs.getbeekon.com/reference/licensing.
The package ships full TypeScript types, so methods, config, and events are typed in your editor. Complete API and guides: docs.getbeekon.com.
Permissions and setup
Beekon does not request permissions on your behalf. Declare them in your app and request them at runtime (for example with PermissionsAndroid or react-native-permissions).
Android
In android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Only if you enable detectActivity -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />While tracking, Android shows a persistent notification (required by the system). Set its title and text with the notification config option.
iOS
In Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Explain why your app uses location.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Explain why your app uses location in the background.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>fetch</string>
</array>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.getbeekon.sdk.sync</string>
</array>
<!-- Only if you enable detectActivity -->
<key>NSMotionUsageDescription</key>
<string>Explain why your app detects activity.</string>Register Beekon's background task once during launch (required for background sync and to resume tracking after termination). In AppDelegate.swift:
import BeekonRn
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
BeekonRnImpl.registerBackgroundTasks()
// ...your existing setup...
return true
}API at a glance
Methods: configure · start · stop · resumeIfNeeded · getCurrentLocation · getLocations · deleteLocations · pendingUploadCount · sync · setExtras · setUserId · addGeofences · removeGeofences · listGeofences · getPermissionStatus · getRequiredPermissions · requestPermission · requestNextNeededPermission · openSettings · licenseStatus · getLog · exportLog · clearLog · setLogLevel · log.
Subscriptions (each returns an unsubscribe function): onState · onLocation · onGeofenceEvent · onSyncStatus · onAuthTokens · onLicenseStatus · onLog.
Every method, type, and event is documented at docs.getbeekon.com and typed in the package.
Notes
- Retention. Fixes are kept for up to 7 days, or the most recent 100,000 fixes, whichever comes first.
- Background relaunch. Call
resumeIfNeeded()early in startup to restore tracking after the system terminates the app. On Android, also resume fromApplication.onCreate(see the example app). - Android background limits. Some manufacturers aggressively stop background services; if tracking halts unexpectedly, see dontkillmyapp.com.
Beekon Cloud
Prefer managed ingest, a console, and server-owned config instead of running your own backend? Beekon Cloud is in private beta — see the docs.
Example
A complete, runnable example is in the example/ directory.
License
Proprietary — evaluation use only without a separate written agreement with WayQ Technologies Pvt Ltd. See LICENSE.txt.
