@wayq/beekon-rn 0.0.3 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BeekonRn.podspec +5 -3
- package/CHANGELOG.md +103 -0
- package/README.md +326 -52
- package/android/build.gradle +9 -4
- package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +411 -59
- package/ios/BeekonRn.mm +103 -24
- package/ios/BeekonRn.swift +465 -61
- package/ios/Frameworks/BeekonKit.xcframework/Info.plist +5 -5
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/BeekonKit +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Info.plist +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.abi.json +11424 -1279
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftinterface +262 -36
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/BeekonKit +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Info.plist +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.abi.json +11424 -1279
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +262 -36
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +11424 -1279
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +262 -36
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +2 -80
- package/lib/module/NativeBeekonRn.js +35 -7
- package/lib/module/NativeBeekonRn.js.map +1 -1
- package/lib/module/beekon.js +246 -45
- package/lib/module/beekon.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal/mappers.js +166 -25
- package/lib/module/internal/mappers.js.map +1 -1
- package/lib/module/types/auth.js +4 -0
- package/lib/module/types/auth.js.map +1 -0
- package/lib/module/types/config.js +2 -0
- package/lib/module/types/enums.js +2 -0
- package/lib/module/types/enums.js.map +1 -0
- package/lib/module/types/error.js +20 -4
- package/lib/module/types/error.js.map +1 -1
- package/lib/module/types/geofence.js +2 -0
- package/lib/module/types/geofence.js.map +1 -0
- package/lib/module/types/location.js +2 -0
- package/lib/module/types/sync.js +2 -0
- package/lib/module/types/sync.js.map +1 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts +150 -20
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
- package/lib/typescript/src/beekon.d.ts +110 -33
- package/lib/typescript/src/beekon.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +6 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal/mappers.d.ts +16 -6
- package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
- package/lib/typescript/src/types/auth.d.ts +99 -0
- package/lib/typescript/src/types/auth.d.ts.map +1 -0
- package/lib/typescript/src/types/config.d.ts +66 -20
- package/lib/typescript/src/types/config.d.ts.map +1 -1
- package/lib/typescript/src/types/enums.d.ts +62 -0
- package/lib/typescript/src/types/enums.d.ts.map +1 -0
- package/lib/typescript/src/types/error.d.ts +21 -5
- package/lib/typescript/src/types/error.d.ts.map +1 -1
- package/lib/typescript/src/types/geofence.d.ts +36 -0
- package/lib/typescript/src/types/geofence.d.ts.map +1 -0
- package/lib/typescript/src/types/location.d.ts +22 -8
- package/lib/typescript/src/types/location.d.ts.map +1 -1
- package/lib/typescript/src/types/state.d.ts +13 -4
- package/lib/typescript/src/types/state.d.ts.map +1 -1
- package/lib/typescript/src/types/sync.d.ts +27 -0
- package/lib/typescript/src/types/sync.d.ts.map +1 -0
- package/package.json +8 -5
- package/scripts/fetch-beekonkit.sh +5 -5
- package/src/NativeBeekonRn.ts +165 -20
- package/src/beekon.ts +278 -48
- package/src/index.tsx +24 -2
- package/src/internal/mappers.ts +242 -27
- package/src/types/auth.ts +101 -0
- package/src/types/config.ts +68 -20
- package/src/types/enums.ts +80 -0
- package/src/types/error.ts +23 -5
- package/src/types/geofence.ts +37 -0
- package/src/types/location.ts +28 -8
- package/src/types/state.ts +13 -3
- package/src/types/sync.ts +23 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeDirectory +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeResources +0 -296
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeSignature +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/_CodeSignature/CodeResources +0 -146
package/BeekonRn.podspec
CHANGED
|
@@ -10,10 +10,12 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package["license"]
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# iOS 17.0 floor reflects this wrapper's React Native baseline (RN 0.85), not
|
|
14
|
+
# a BeekonKit constraint — BeekonKit 0.0.6 itself supports iOS 13+ (with
|
|
15
|
+
# 13–16 fallback paths). Kept at 17.0 to avoid any consumer regression; do not
|
|
16
|
+
# lower below React Native's own minimum.
|
|
15
17
|
s.platforms = { :ios => "17.0" }
|
|
16
|
-
s.source = { :git => "https://github.com/wayqteam/beekon.git", :tag => "v#{s.version}" }
|
|
18
|
+
s.source = { :git => "https://github.com/wayqteam/beekon-rn.git", :tag => "v#{s.version}" }
|
|
17
19
|
|
|
18
20
|
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
19
21
|
# Headers are only for the auto-generated `BeekonRn-Swift.h` interop — keep
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@wayq/beekon-rn` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
Beekon is pre-1.0 — releases may contain breaking changes.
|
|
8
|
+
|
|
9
|
+
## [0.0.6]
|
|
10
|
+
|
|
11
|
+
Built against the native **0.0.6** API; requires native ≥ 0.0.6 at runtime.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Native token refresh** — `SyncConfig.auth` (`AuthConfig`) lets the SDK attach
|
|
16
|
+
and natively refresh the upload access token, proactively before expiry and
|
|
17
|
+
reactively on a `401`/`403`, and retry the upload — all natively, so it works in
|
|
18
|
+
the background and on a cold launch with no host involvement. Rotated credentials
|
|
19
|
+
surface on the new `Beekon.onAuthTokens()` subscription (`AuthTokens`). Adds the
|
|
20
|
+
`AuthConfig`, `AuthResponseMapping`, `AuthTokens` types and the `AuthStrategy` /
|
|
21
|
+
`AuthBodyFormat` enums. Omitting `auth` keeps the legacy static-`headers`
|
|
22
|
+
behaviour. The refresh recipe is persisted in plaintext to survive cold launch —
|
|
23
|
+
do not put static client secrets in `refreshHeaders`/`refreshPayload`.
|
|
24
|
+
- **`getCurrentLocation({ timeoutMs, accuracy })`** — a one-shot current location,
|
|
25
|
+
independent of any tracking session (resolves `null` on timeout; never starts or
|
|
26
|
+
stops tracking; the fix is not persisted and does not appear on `onLocation`).
|
|
27
|
+
Re-introduces thrown `BeekonError` kinds `'permissionDenied'`,
|
|
28
|
+
`'locationServicesDisabled'`, and `'locationUnavailable'` on a precondition
|
|
29
|
+
failure (0.0.5 had removed the `PERMISSION_DENIED` / `LOCATION_SERVICES_DISABLED`
|
|
30
|
+
thrown errors; they now surface again, but only from `getCurrentLocation()` —
|
|
31
|
+
tracking-lifecycle problems still report through `onState` as `Stopped(reason)`).
|
|
32
|
+
- **`NotificationConfig.smallIcon`** — a custom Android status-bar icon (drawable /
|
|
33
|
+
mipmap resource name) for the foreground-service tracking notification.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- `androidNotification` (type `AndroidNotificationConfig`) renamed to `notification`
|
|
38
|
+
(type `NotificationConfig`) — **breaking**. The config remains Android-only; iOS
|
|
39
|
+
ignores it.
|
|
40
|
+
- `deleteLocations(before)` cutoff is now strictly **before** `before` (exclusive
|
|
41
|
+
`<`), aligning both natives and all wrappers; the prior wording said "at or
|
|
42
|
+
before".
|
|
43
|
+
- `resumeIfNeeded()` now calls the guarded native `Beekon.resumeIfNeeded()` on
|
|
44
|
+
Android (previously `Beekon.start()`): it re-adopts a previously-active,
|
|
45
|
+
non-user-stopped session only, mirroring iOS.
|
|
46
|
+
- Native pins bumped to `0.0.6` (Maven `io.github.wayqteam:beekon`, iOS
|
|
47
|
+
`BeekonKit.xcframework`).
|
|
48
|
+
|
|
49
|
+
## [0.0.5]
|
|
50
|
+
|
|
51
|
+
Full rebuild against the native **0.0.5** API — a breaking, no-backward-compat
|
|
52
|
+
release. The TypeScript surface is a faithful 1:1 mirror of the native `Beekon`
|
|
53
|
+
(Android) / `Beekon.shared` (iOS).
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- **Server sync**: `SyncConfig` on `BeekonConfig`, plus `sync()`, `setExtras()`,
|
|
58
|
+
`pendingUploadCount()`, and the `onSyncStatus` subscription
|
|
59
|
+
(`SyncIdle`/`SyncPending`/`SyncFailed`).
|
|
60
|
+
- **Geofencing**: `addGeofences()` / `removeGeofences()` / `listGeofences()` and
|
|
61
|
+
the `onGeofenceEvent` subscription (`BeekonGeofence`, `GeofenceEvent`,
|
|
62
|
+
`Transition`).
|
|
63
|
+
- **Richer config**: `accuracyMode`, `whenStationary`, `stationaryRadiusMeters`,
|
|
64
|
+
`detectActivity`.
|
|
65
|
+
- **Richer `Location`**: `id`, `quality`, `trigger`, `motion`, `activity`,
|
|
66
|
+
`isMock`.
|
|
67
|
+
- `deleteLocations(before)`, `resumeIfNeeded()` (wrapper-only cold-launch resume,
|
|
68
|
+
not part of the native spec), and `StopReason 'locationUnavailable'`.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- `intervalSeconds` → `minTimeBetweenLocationsSeconds`; `distanceMeters` →
|
|
73
|
+
`minDistanceBetweenLocationsMeters`.
|
|
74
|
+
- `getLocations(from: Date, to: Date)` replaces the prior history call.
|
|
75
|
+
- Notification config is now `androidNotification` (Android-only; iOS ignores it).
|
|
76
|
+
- Native pins bumped to `0.0.5` (Maven `io.github.wayqteam:beekon`, SwiftPM
|
|
77
|
+
`beekon-ios-binary`).
|
|
78
|
+
|
|
79
|
+
### Removed
|
|
80
|
+
|
|
81
|
+
- `PERMISSION_DENIED` / `LOCATION_SERVICES_DISABLED` thrown errors — permission
|
|
82
|
+
and service problems now surface only on `onState` as `Stopped(reason)`.
|
|
83
|
+
|
|
84
|
+
## [0.0.3]
|
|
85
|
+
|
|
86
|
+
First synchronized release across all four registries (Maven Central,
|
|
87
|
+
`wayqteam/beekon-ios-binary` xcframework, pub.dev, npm). `Location`
|
|
88
|
+
accuracy/speed/bearing/altitude are nullable to faithfully represent providers
|
|
89
|
+
that don't deliver them.
|
|
90
|
+
|
|
91
|
+
## [0.0.1]
|
|
92
|
+
|
|
93
|
+
Initial release.
|
|
94
|
+
|
|
95
|
+
### Added
|
|
96
|
+
|
|
97
|
+
- React Native (New Architecture / TurboModule) binding for the native Beekon
|
|
98
|
+
location SDKs (Android `io.github.wayqteam:beekon`, iOS `BeekonKit`
|
|
99
|
+
xcframework).
|
|
100
|
+
- Public API mirroring the native surface: `Beekon.configure / start / stop /
|
|
101
|
+
getLocations`, plus `onState` / `onLocation` subscriptions.
|
|
102
|
+
- `BeekonConfig`, `BeekonState` (`idle → tracking → stopped(reason)`),
|
|
103
|
+
`Location`, and typed `BeekonError` kinds.
|
package/README.md
CHANGED
|
@@ -1,43 +1,70 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/icon.png" alt="Beekon" width="140" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">@wayq/beekon-rn</h1>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
Background location tracking for React Native.<br/>
|
|
9
|
+
Native location stack on each platform — tracking survives backgrounding and termination.
|
|
10
|
+
</p>
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/@wayq/beekon-rn"><img alt="npm" src="https://img.shields.io/npm/v/@wayq/beekon-rn?label=npm&logo=npm&logoColor=white&color=CB3837&style=flat-square"></a>
|
|
14
|
+
<img alt="React Native · New Architecture" src="https://img.shields.io/badge/React%20Native-New%20Arch-61DAFB?logo=react&logoColor=white&style=flat-square">
|
|
15
|
+
<img alt="Platforms · Android | iOS" src="https://img.shields.io/badge/platforms-Android%20%7C%20iOS-61DAFB?style=flat-square">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="https://docs.getbeekon.com"><strong>Docs</strong></a> ·
|
|
20
|
+
<a href="https://console.getbeekon.com"><strong>Console</strong></a> ·
|
|
21
|
+
<a href="https://getbeekon.com"><strong>getbeekon.com</strong></a> ·
|
|
22
|
+
<a href="https://github.com/wayqteam/beekon"><strong>Umbrella</strong></a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Capture GPS in the foreground and background, keep a queryable history on the device, define geofences, and optionally sync to your own server. The JavaScript API is fully typed.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- Foreground and background tracking that survives app termination
|
|
32
|
+
- Battery-aware capture: time and distance filtering, accuracy presets, and automatic pausing while the device is stationary
|
|
33
|
+
- On-device history you can query at any time
|
|
34
|
+
- Geofencing with enter and exit events
|
|
35
|
+
- Optional batched server sync with automatic retry
|
|
36
|
+
- Activity detection (walking, running, cycling, automotive)
|
|
37
|
+
- Built for the React Native New Architecture
|
|
8
38
|
|
|
9
39
|
## Requirements
|
|
10
40
|
|
|
11
|
-
|
|
|
41
|
+
| | Minimum |
|
|
12
42
|
|---|---|
|
|
13
|
-
| React Native | 0.76
|
|
43
|
+
| React Native | 0.76 (New Architecture) |
|
|
14
44
|
| iOS | 17.0 |
|
|
15
|
-
| Android | API 26 |
|
|
16
|
-
| New Architecture | required (Old Arch is unsupported) |
|
|
45
|
+
| Android | 8.0 (API level 26) |
|
|
17
46
|
|
|
18
|
-
##
|
|
47
|
+
## Installation
|
|
19
48
|
|
|
20
49
|
```sh
|
|
21
50
|
npm install @wayq/beekon-rn
|
|
22
|
-
# or
|
|
23
|
-
yarn add @wayq/beekon-rn
|
|
24
51
|
```
|
|
25
52
|
|
|
26
|
-
iOS:
|
|
53
|
+
**iOS** — install pods:
|
|
27
54
|
|
|
28
55
|
```sh
|
|
29
56
|
cd ios && pod install
|
|
30
57
|
```
|
|
31
58
|
|
|
32
|
-
|
|
59
|
+
**Android** — no additional steps; the module links automatically.
|
|
33
60
|
|
|
34
|
-
|
|
61
|
+
## Permissions and setup
|
|
35
62
|
|
|
36
|
-
|
|
63
|
+
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`).
|
|
37
64
|
|
|
38
|
-
|
|
65
|
+
### Android
|
|
39
66
|
|
|
40
|
-
|
|
67
|
+
In `android/app/src/main/AndroidManifest.xml`:
|
|
41
68
|
|
|
42
69
|
```xml
|
|
43
70
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
@@ -45,72 +72,319 @@ The library does NOT request permissions itself — your app must. Use a library
|
|
|
45
72
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
46
73
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
|
47
74
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
75
|
+
<!-- Only if you enable detectActivity -->
|
|
76
|
+
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
|
48
77
|
```
|
|
49
78
|
|
|
50
|
-
|
|
79
|
+
While tracking, Android shows a persistent notification (required by the system). Set its title and text with the `notification` option.
|
|
80
|
+
|
|
81
|
+
### iOS
|
|
82
|
+
|
|
83
|
+
In `Info.plist`:
|
|
51
84
|
|
|
52
85
|
```xml
|
|
53
86
|
<key>NSLocationWhenInUseUsageDescription</key>
|
|
54
|
-
<string
|
|
87
|
+
<string>Explain why your app uses location.</string>
|
|
55
88
|
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
56
|
-
<string
|
|
89
|
+
<string>Explain why your app uses location in the background.</string>
|
|
57
90
|
<key>UIBackgroundModes</key>
|
|
58
|
-
<array
|
|
91
|
+
<array>
|
|
92
|
+
<string>location</string>
|
|
93
|
+
<string>fetch</string>
|
|
94
|
+
</array>
|
|
95
|
+
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
|
96
|
+
<array>
|
|
97
|
+
<string>in.wayq.beekon.sync</string>
|
|
98
|
+
</array>
|
|
99
|
+
<!-- Only if you enable detectActivity -->
|
|
100
|
+
<key>NSMotionUsageDescription</key>
|
|
101
|
+
<string>Explain why your app detects activity.</string>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Register Beekon's background task once during launch (required for background sync and to resume tracking after the app is terminated). In `AppDelegate.swift`:
|
|
105
|
+
|
|
106
|
+
```swift
|
|
107
|
+
import BeekonRn
|
|
108
|
+
|
|
109
|
+
func application(
|
|
110
|
+
_ application: UIApplication,
|
|
111
|
+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
112
|
+
) -> Bool {
|
|
113
|
+
BeekonRnImpl.registerBackgroundTasks()
|
|
114
|
+
// ...your existing setup...
|
|
115
|
+
return true
|
|
116
|
+
}
|
|
59
117
|
```
|
|
60
118
|
|
|
61
119
|
## Usage
|
|
62
120
|
|
|
121
|
+
### Start tracking
|
|
122
|
+
|
|
63
123
|
```ts
|
|
64
|
-
import { Beekon
|
|
124
|
+
import { Beekon } from '@wayq/beekon-rn';
|
|
65
125
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const offLoc = Beekon.onLocation((l: Location) => console.log('location', l));
|
|
126
|
+
const offState = Beekon.onState((state) => {
|
|
127
|
+
console.log('state:', state.kind); // 'idle' | 'tracking' | 'stopped'
|
|
128
|
+
});
|
|
70
129
|
|
|
71
|
-
|
|
130
|
+
const offLocation = Beekon.onLocation((location) => {
|
|
131
|
+
console.log(location.latitude, location.longitude, location.timestamp);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Configure is optional. Request OS permissions before starting.
|
|
72
135
|
await Beekon.configure({
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
androidNotification: {
|
|
76
|
-
title: 'Tracking',
|
|
77
|
-
text: 'Recording your route',
|
|
78
|
-
smallIconResName: 'ic_notification', // drawable in your app
|
|
79
|
-
},
|
|
136
|
+
minTimeBetweenLocationsSeconds: 30,
|
|
137
|
+
minDistanceBetweenLocationsMeters: 100,
|
|
80
138
|
});
|
|
81
139
|
|
|
82
140
|
await Beekon.start();
|
|
83
|
-
|
|
141
|
+
|
|
142
|
+
// Later:
|
|
84
143
|
await Beekon.stop();
|
|
144
|
+
offState();
|
|
145
|
+
offLocation();
|
|
146
|
+
```
|
|
85
147
|
|
|
86
|
-
|
|
87
|
-
const fixes = await Beekon.history(new Date(Date.now() - 3600_000), new Date());
|
|
148
|
+
`start()` and `stop()` never throw. Observe `onState` to learn whether tracking began and why it stopped:
|
|
88
149
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
150
|
+
```ts
|
|
151
|
+
Beekon.onState((state) => {
|
|
152
|
+
if (state.kind === 'stopped') {
|
|
153
|
+
// 'user' | 'permissionDenied' | 'locationServicesDisabled'
|
|
154
|
+
// | 'locationUnavailable' | 'system'
|
|
155
|
+
console.log('stopped:', state.reason);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Read history
|
|
161
|
+
|
|
162
|
+
Recorded fixes are stored on the device and remain available even after the app is closed.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
|
166
|
+
const fixes = await Beekon.getLocations(since, new Date());
|
|
167
|
+
|
|
168
|
+
await Beekon.deleteLocations(); // delete everything
|
|
169
|
+
await Beekon.deleteLocations(since); // delete up to a cutoff
|
|
92
170
|
```
|
|
93
171
|
|
|
172
|
+
### Geofences
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
await Beekon.addGeofences([
|
|
176
|
+
{ id: 'office', latitude: 37.331, longitude: -122.031, radiusMeters: 150 },
|
|
177
|
+
]);
|
|
178
|
+
|
|
179
|
+
const offGeofence = Beekon.onGeofenceEvent((event) => {
|
|
180
|
+
console.log(event.geofenceId, event.type); // 'enter' | 'exit'
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
await Beekon.listGeofences();
|
|
184
|
+
await Beekon.removeGeofences(['office']);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Server sync
|
|
188
|
+
|
|
189
|
+
Add a `sync` config to upload recorded fixes and geofence events to your backend. Uploads are batched, retried automatically, and removed from the device once your server accepts them. Without a `sync` config, all data stays on the device.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
await Beekon.configure({
|
|
193
|
+
sync: {
|
|
194
|
+
url: 'https://api.example.com/locations',
|
|
195
|
+
headers: { Authorization: 'Bearer <token>' },
|
|
196
|
+
// intervalSeconds defaults to 300, batchSize to 100
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
Beekon.setExtras({ userId: 'abc123' }); // attached to every upload
|
|
201
|
+
|
|
202
|
+
Beekon.onSyncStatus((status) => {
|
|
203
|
+
console.log('sync:', status.kind); // 'idle' | 'pending' | 'failed'
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Token refresh
|
|
208
|
+
|
|
209
|
+
Set `sync.auth` (an `AuthConfig`) to let the SDK attach and **natively** refresh the upload access token — proactively before it expires and reactively on a `401`/`403`, then retry the upload. This runs in the background and survives a cold launch with no host involvement. Without `auth`, a `401`/`403` pauses sync and surfaces `SyncFailure 'auth'`; re-seed by calling `configure()` again to resume.
|
|
210
|
+
|
|
211
|
+
The supplied tokens are a **seed**: the SDK owns and rotates the live token set in secure storage (Keychain / encrypted prefs) after first persist. Subscribe with `onAuthTokens` to mirror rotations into your own session store.
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
await Beekon.configure({
|
|
215
|
+
sync: {
|
|
216
|
+
url: 'https://api.example.com/locations',
|
|
217
|
+
auth: {
|
|
218
|
+
accessToken: '<initial access token>',
|
|
219
|
+
refreshToken: '<initial refresh token>',
|
|
220
|
+
expiresAt: new Date(Date.now() + 3600_000),
|
|
221
|
+
refreshUrl: 'https://auth.example.com/oauth/token',
|
|
222
|
+
refreshPayload: {
|
|
223
|
+
grant_type: 'refresh_token',
|
|
224
|
+
refresh_token: '{refreshToken}', // substituted with the current token
|
|
225
|
+
},
|
|
226
|
+
// strategy defaults to 'bearer', refreshBodyFormat to 'form',
|
|
227
|
+
// skewMarginSeconds to 60. responseMapping defaults to common-name detection.
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const offAuth = Beekon.onAuthTokens((tokens) => {
|
|
233
|
+
// Persist the rotated set into your own session store.
|
|
234
|
+
console.log('rotated:', tokens.accessToken, tokens.expiresAt, tokens.epoch);
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The refresh recipe is persisted in plaintext to survive a cold launch — **do not** put static client secrets in `refreshHeaders` or `refreshPayload`. Requires the native SDK ≥ 0.0.6; with an older native binary the recipe is ignored and only static `sync.headers` apply.
|
|
239
|
+
|
|
240
|
+
## Configuration
|
|
241
|
+
|
|
242
|
+
All options are optional; defaults are shown.
|
|
243
|
+
|
|
244
|
+
| Option | Default | Description |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| `minTimeBetweenLocationsSeconds` | `30` | Minimum seconds between recorded fixes. `0` disables the time filter. |
|
|
247
|
+
| `minDistanceBetweenLocationsMeters` | `100` | Minimum metres between recorded fixes. `0` disables the distance filter. |
|
|
248
|
+
| `accuracyMode` | `'balanced'` | `'high'` \| `'balanced'` \| `'low'`. Trades accuracy against battery. |
|
|
249
|
+
| `whenStationary` | `'pause'` | `'keepTracking'` \| `'pause'` \| `'pauseWithCheckIns'`. |
|
|
250
|
+
| `stationaryRadiusMeters` | `5` | Distance the device must move to count as moving again. |
|
|
251
|
+
| `detectActivity` | `false` | Detect physical activity. Requires the motion permission. |
|
|
252
|
+
| `sync` | – | Server upload settings: `{ url, headers?, intervalSeconds?, batchSize?, auth? }`. See [Token refresh](#token-refresh). |
|
|
253
|
+
| `notification` | – | Android-only tracking notification: `{ title?, text?, smallIcon? }`. `smallIcon` is a drawable/mipmap resource name. |
|
|
254
|
+
|
|
255
|
+
A fix is recorded only when **both** the time and distance filters are satisfied.
|
|
256
|
+
|
|
94
257
|
## API
|
|
95
258
|
|
|
96
259
|
| Method | Description |
|
|
97
260
|
|---|---|
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
261
|
+
| `configure(config)` | Apply settings. Optional; may be called while tracking. |
|
|
262
|
+
| `start()` | Begin tracking. |
|
|
263
|
+
| `stop()` | Stop tracking. |
|
|
264
|
+
| `resumeIfNeeded()` | Resume a session that was active before the app closed. |
|
|
265
|
+
| `getCurrentLocation(options?)` | One-shot current fix, independent of tracking. Resolves `null` on timeout. `options`: `{ timeoutMs?, accuracy? }`. |
|
|
266
|
+
| `getLocations(from, to)` | Recorded fixes within a date range. |
|
|
267
|
+
| `deleteLocations(before?)` | Delete fixes (all if `before` is omitted); returns the count removed. |
|
|
268
|
+
| `pendingUploadCount()` | Number of fixes not yet uploaded. |
|
|
269
|
+
| `sync()` | Request an immediate upload. |
|
|
270
|
+
| `setExtras(extras)` | Custom fields included with every upload. |
|
|
271
|
+
| `addGeofences(geofences)` | Register circular regions. |
|
|
272
|
+
| `removeGeofences(ids)` | Unregister geofences by id. |
|
|
273
|
+
| `listGeofences()` | Currently registered geofences. |
|
|
274
|
+
|
|
275
|
+
Subscriptions — each returns an unsubscribe function:
|
|
276
|
+
|
|
277
|
+
| Subscription | Delivers |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `onState(cb)` | Tracking state changes. The current state is delivered immediately. |
|
|
280
|
+
| `onLocation(cb)` | Each newly recorded fix. |
|
|
281
|
+
| `onGeofenceEvent(cb)` | Geofence enter and exit events. |
|
|
282
|
+
| `onSyncStatus(cb)` | Upload status. The current status is delivered immediately. |
|
|
283
|
+
| `onAuthTokens(cb)` | Token rotations from native refresh (see [Token refresh](#token-refresh)). The latest rotation is delivered immediately. |
|
|
104
284
|
|
|
105
|
-
|
|
285
|
+
`getLocations`, `deleteLocations`, `pendingUploadCount`, and `addGeofences` reject with a `BeekonError` on failure — check `error.kind` (`'storage'` or `'invalidGeofence'`). `getCurrentLocation` rejects with `error.kind` `'permissionDenied'`, `'locationServicesDisabled'`, or `'locationUnavailable'` on a precondition failure. Other methods resolve normally; tracking-lifecycle problems are reported through `onState` rather than thrown.
|
|
106
286
|
|
|
107
|
-
|
|
108
|
-
`'permissionDenied'`, `'locationServicesDisabled'`, `'storageFailure'`.
|
|
287
|
+
## Types
|
|
109
288
|
|
|
110
|
-
|
|
289
|
+
```ts
|
|
290
|
+
type Location = {
|
|
291
|
+
id: string;
|
|
292
|
+
latitude: number;
|
|
293
|
+
longitude: number;
|
|
294
|
+
timestamp: Date;
|
|
295
|
+
accuracy: number | null; // metres
|
|
296
|
+
speed: number | null; // m/s
|
|
297
|
+
bearing: number | null; // degrees from true north
|
|
298
|
+
altitude: number | null; // metres
|
|
299
|
+
quality: 'ok' | 'lowAccuracy' | 'implausibleSpeed';
|
|
300
|
+
trigger: 'interval' | 'motion' | 'checkIn' | 'geofence' | 'manual';
|
|
301
|
+
motion: 'moving' | 'stationary' | 'unknown';
|
|
302
|
+
activity:
|
|
303
|
+
| 'stationary' | 'walking' | 'running'
|
|
304
|
+
| 'cycling' | 'automotive' | 'unknown' | null;
|
|
305
|
+
isMock: boolean;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
type BeekonState =
|
|
309
|
+
| { kind: 'idle' }
|
|
310
|
+
| { kind: 'tracking' }
|
|
311
|
+
| {
|
|
312
|
+
kind: 'stopped';
|
|
313
|
+
reason:
|
|
314
|
+
| 'user' | 'permissionDenied' | 'locationServicesDisabled'
|
|
315
|
+
| 'locationUnavailable' | 'system';
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
type SyncStatus =
|
|
319
|
+
| { kind: 'idle' }
|
|
320
|
+
| { kind: 'pending' }
|
|
321
|
+
| { kind: 'failed'; reason: 'auth' | 'rejected' };
|
|
322
|
+
|
|
323
|
+
type BeekonGeofence = {
|
|
324
|
+
id: string;
|
|
325
|
+
latitude: number;
|
|
326
|
+
longitude: number;
|
|
327
|
+
radiusMeters: number;
|
|
328
|
+
notifyOnEntry?: boolean; // default true
|
|
329
|
+
notifyOnExit?: boolean; // default true
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
type GeofenceEvent = {
|
|
333
|
+
id: string;
|
|
334
|
+
geofenceId: string;
|
|
335
|
+
type: 'enter' | 'exit';
|
|
336
|
+
timestamp: Date;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// Set on `SyncConfig.auth` to enable native token refresh. The token fields are
|
|
340
|
+
// a seed — the SDK rotates them after first persist.
|
|
341
|
+
type AuthConfig = {
|
|
342
|
+
accessToken?: string;
|
|
343
|
+
refreshToken?: string;
|
|
344
|
+
expiresAt?: Date;
|
|
345
|
+
strategy?: 'bearer' | 'raw'; // default 'bearer'
|
|
346
|
+
refreshUrl?: string; // omit to disable refresh
|
|
347
|
+
refreshPayload?: Record<string, string>; // '{refreshToken}' substituted
|
|
348
|
+
refreshHeaders?: Record<string, string>; // '{accessToken}' substituted
|
|
349
|
+
refreshBodyFormat?: 'form' | 'json'; // default 'form'
|
|
350
|
+
responseMapping?: {
|
|
351
|
+
accessToken?: string;
|
|
352
|
+
refreshToken?: string;
|
|
353
|
+
expiresIn?: string;
|
|
354
|
+
expiresAt?: string;
|
|
355
|
+
};
|
|
356
|
+
skewMarginSeconds?: number; // default 60
|
|
357
|
+
seedEpoch?: number;
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// Delivered by `onAuthTokens` after each native rotation. Sensitive — in-process
|
|
361
|
+
// only, never logged.
|
|
362
|
+
type AuthTokens = {
|
|
363
|
+
accessToken: string;
|
|
364
|
+
refreshToken: string | null;
|
|
365
|
+
expiresAt: Date | null;
|
|
366
|
+
epoch: number; // monotonic generation, bumped on each refresh
|
|
367
|
+
};
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Optional numeric fields on `Location` are `null` when the device did not report them — never `0`.
|
|
371
|
+
|
|
372
|
+
## Notes
|
|
111
373
|
|
|
112
|
-
|
|
374
|
+
- **Retention.** Fixes are kept on the device for up to 7 days, or the most recent 100,000 fixes, whichever comes first.
|
|
375
|
+
- **Background relaunch.** Call `resumeIfNeeded()` early in your app to restore tracking after the system terminates it. On Android, also resume from your `Application.onCreate` (see the example app).
|
|
376
|
+
- **Android background limits.** Some manufacturers aggressively stop background services; if tracking halts unexpectedly, see [dontkillmyapp.com](https://dontkillmyapp.com).
|
|
377
|
+
|
|
378
|
+
## Example
|
|
379
|
+
|
|
380
|
+
A complete, runnable example is in the [`example/`](./example) directory.
|
|
113
381
|
|
|
114
382
|
## License
|
|
115
383
|
|
|
116
|
-
Proprietary —
|
|
384
|
+
Proprietary — evaluation use only without a separate written agreement with wayqteam. See [LICENSE.txt](./LICENSE.txt).
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
<p align="center">
|
|
389
|
+
© WayQ Technologies Pvt Ltd
|
|
390
|
+
</p>
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
buildscript {
|
|
2
2
|
ext.BeekonRn = [
|
|
3
3
|
kotlinVersion: "2.1.20",
|
|
4
|
-
|
|
4
|
+
// minSdk 26 is required by the native Beekon AAR (io.github.wayqteam:beekon).
|
|
5
|
+
minSdkVersion: 26,
|
|
5
6
|
compileSdkVersion: 36,
|
|
6
7
|
targetSdkVersion: 36
|
|
7
8
|
]
|
|
@@ -57,8 +58,12 @@ android {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
compileOptions {
|
|
60
|
-
sourceCompatibility JavaVersion.
|
|
61
|
-
targetCompatibility JavaVersion.
|
|
61
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
62
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
kotlinOptions {
|
|
66
|
+
jvmTarget = "17"
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
|
|
@@ -72,7 +77,7 @@ dependencies {
|
|
|
72
77
|
// Native Beekon SDK — published from beekon-android/ via Maven Central.
|
|
73
78
|
// Pinned exact in v0.x to avoid surprise breakage; loosen to a range when
|
|
74
79
|
// the SDK reaches v1 stability.
|
|
75
|
-
implementation "io.github.wayqteam:beekon:0.0.
|
|
80
|
+
implementation "io.github.wayqteam:beekon:0.0.6"
|
|
76
81
|
// Kotlin coroutines — required for collecting Beekon's StateFlow/SharedFlow.
|
|
77
82
|
// Beekon already depends on coroutines transitively, but declaring it here
|
|
78
83
|
// makes the dependency intent explicit.
|