spotny-sdk 0.3.2 → 0.3.3
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/README.md +293 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,26 +1,312 @@
|
|
|
1
1
|
# spotny-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A React Native SDK for iBeacon scanning powered by KontaktSDK (iOS) and AltBeacon (Android). Detects proximity beacons, fires region enter/exit events, and integrates with the Spotny campaign backend.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> Requires **React Native 0.73+** with the New Architecture (Turbo Modules) enabled.
|
|
6
|
+
|
|
7
|
+
---
|
|
6
8
|
|
|
9
|
+
## Installation
|
|
7
10
|
|
|
8
11
|
```sh
|
|
9
12
|
npm install spotny-sdk
|
|
13
|
+
# or
|
|
14
|
+
yarn add spotny-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### iOS
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
cd ios && pod install
|
|
10
21
|
```
|
|
11
22
|
|
|
23
|
+
Add the following keys to your `Info.plist`:
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
```xml
|
|
26
|
+
<key>NSLocationWhenInUseUsageDescription</key>
|
|
27
|
+
<string>We use your location to detect nearby beacons.</string>
|
|
28
|
+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
29
|
+
<string>We use your location in the background to detect nearby beacons.</string>
|
|
30
|
+
<key>NSBluetoothAlwaysUsageDescription</key>
|
|
31
|
+
<string>We use Bluetooth to scan for nearby beacons.</string>
|
|
32
|
+
```
|
|
14
33
|
|
|
34
|
+
Enable **Background Modes** in Xcode → Signing & Capabilities:
|
|
35
|
+
- Location updates
|
|
36
|
+
- Uses Bluetooth LE accessories
|
|
15
37
|
|
|
16
|
-
|
|
17
|
-
import { multiply } from 'spotny-sdk';
|
|
38
|
+
### Android
|
|
18
39
|
|
|
19
|
-
|
|
40
|
+
Add to `AndroidManifest.xml`:
|
|
20
41
|
|
|
21
|
-
|
|
42
|
+
```xml
|
|
43
|
+
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
|
44
|
+
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
45
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
46
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
47
|
+
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
|
22
48
|
```
|
|
23
49
|
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { useEffect } from 'react';
|
|
56
|
+
import {
|
|
57
|
+
configure,
|
|
58
|
+
startScanner,
|
|
59
|
+
stopScanner,
|
|
60
|
+
addBeaconsRangedListener,
|
|
61
|
+
addBeaconRegionListener,
|
|
62
|
+
} from 'spotny-sdk';
|
|
63
|
+
|
|
64
|
+
export default function App() {
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
// Optional: override defaults before starting
|
|
67
|
+
configure({ maxDetectionDistance: 10 });
|
|
68
|
+
|
|
69
|
+
// Start scanning with a unique device/user identifier
|
|
70
|
+
startScanner('device-uuid-here', /* userId */ null);
|
|
71
|
+
|
|
72
|
+
// Listen for ranged beacons (fires ~every second)
|
|
73
|
+
const rangedSub = addBeaconsRangedListener(({ beacons, region }) => {
|
|
74
|
+
console.log('Beacons in range:', beacons);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Listen for region enter / exit
|
|
78
|
+
const regionSub = addBeaconRegionListener(({ region, event }) => {
|
|
79
|
+
console.log(`Region ${region}: ${event}`);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
stopScanner();
|
|
84
|
+
rangedSub.remove();
|
|
85
|
+
regionSub.remove();
|
|
86
|
+
};
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## API Reference
|
|
96
|
+
|
|
97
|
+
### Core Scanning
|
|
98
|
+
|
|
99
|
+
#### `startScanner(userUUID, userId?)`
|
|
100
|
+
|
|
101
|
+
Starts BLE beacon scanning and begins ranging / monitoring regions.
|
|
102
|
+
|
|
103
|
+
| Parameter | Type | Required | Description |
|
|
104
|
+
|------------|------------------|----------|--------------------------------------------------|
|
|
105
|
+
| `userUUID` | `string` | Yes | Unique identifier for this installation/session |
|
|
106
|
+
| `userId` | `number \| null` | No | Authenticated user ID (sent to the backend) |
|
|
107
|
+
|
|
108
|
+
Returns `Promise<string>` — resolves with a status message.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
await startScanner('550e8400-e29b-41d4-a716-446655440000', 42);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
#### `stopScanner()`
|
|
117
|
+
|
|
118
|
+
Stops scanning, halts ranging, and clears all in-memory beacon state.
|
|
119
|
+
|
|
120
|
+
Returns `Promise<string>`.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
await stopScanner();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
#### `isScanning()`
|
|
129
|
+
|
|
130
|
+
Returns `Promise<boolean>` — `true` if the SDK is currently scanning.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const scanning = await isScanning();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### Configuration
|
|
139
|
+
|
|
140
|
+
#### `configure(config)`
|
|
141
|
+
|
|
142
|
+
Overrides SDK defaults. **Must be called before `startScanner`.**
|
|
143
|
+
|
|
144
|
+
| Option | Type | Default | Description |
|
|
145
|
+
|-----------------------|----------|----------------------------|------------------------------------------|
|
|
146
|
+
| `backendURL` | `string` | `https://api.spotny.app` | Base URL for the Spotny campaign API |
|
|
147
|
+
| `maxDetectionDistance`| `number` | `8.0` | Maximum beacon detection radius (metres) |
|
|
148
|
+
|
|
149
|
+
Returns `Promise<string>`.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
await configure({
|
|
153
|
+
backendURL: 'https://api.spotny.app',
|
|
154
|
+
maxDetectionDistance: 12,
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### Permissions
|
|
161
|
+
|
|
162
|
+
#### `requestNotificationPermissions()` *(iOS only)*
|
|
163
|
+
|
|
164
|
+
Prompts the user for local-notification permissions. Safe to call on Android (no-op).
|
|
165
|
+
|
|
166
|
+
Returns `Promise<string>`.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
await requestNotificationPermissions();
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Event Listeners
|
|
175
|
+
|
|
176
|
+
#### `addBeaconsRangedListener(callback)`
|
|
177
|
+
|
|
178
|
+
Fires approximately every second while beacons are within `maxDetectionDistance`.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const subscription = addBeaconsRangedListener(({ beacons, region }) => {
|
|
182
|
+
beacons.forEach(b => {
|
|
183
|
+
console.log(`${b.uuid} — ${b.distance.toFixed(1)} m (${b.proximity})`);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// When done:
|
|
188
|
+
subscription.remove();
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Callback payload — `BeaconRangedEvent`:**
|
|
192
|
+
|
|
193
|
+
| Field | Type | Description |
|
|
194
|
+
|-----------|----------------|--------------------------------|
|
|
195
|
+
| `beacons` | `BeaconData[]` | Array of visible beacons |
|
|
196
|
+
| `region` | `string` | Beacon region identifier |
|
|
197
|
+
|
|
198
|
+
**`BeaconData`:**
|
|
199
|
+
|
|
200
|
+
| Field | Type | Description |
|
|
201
|
+
|-------------|----------|-------------------------------------------------------|
|
|
202
|
+
| `uuid` | `string` | Proximity UUID |
|
|
203
|
+
| `major` | `number` | Major value |
|
|
204
|
+
| `minor` | `number` | Minor value |
|
|
205
|
+
| `distance` | `number` | Estimated distance in metres |
|
|
206
|
+
| `rssi` | `number` | Signal strength (dBm) |
|
|
207
|
+
| `proximity` | `string` | `'immediate'` \| `'near'` \| `'far'` \| `'unknown'` |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
#### `addBeaconRegionListener(callback)`
|
|
212
|
+
|
|
213
|
+
Fires on region enter, exit, and state-determination events. Works in **foreground, background, and terminated state** (iOS).
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
const subscription = addBeaconRegionListener(({ region, event, state }) => {
|
|
217
|
+
if (event === 'enter') console.log('Entered', region);
|
|
218
|
+
if (event === 'exit') console.log('Exited', region);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// When done:
|
|
222
|
+
subscription.remove();
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Callback payload — `BeaconRegionEvent`:**
|
|
226
|
+
|
|
227
|
+
| Field | Type | Description |
|
|
228
|
+
|----------|----------|---------------------------------------------------------|
|
|
229
|
+
| `region` | `string` | Region identifier |
|
|
230
|
+
| `event` | `string` | `'enter'` \| `'exit'` \| `'determined'` |
|
|
231
|
+
| `state` | `string` | `'inside'` \| `'outside'` \| `'unknown'` (determined only) |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### Debounce Helpers
|
|
236
|
+
|
|
237
|
+
These let you tune how often repeated proximity events are emitted for the same beacon.
|
|
238
|
+
|
|
239
|
+
#### `setDebounceInterval(seconds)`
|
|
240
|
+
|
|
241
|
+
Sets the minimum gap (in seconds) between proximity events for the same beacon.
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
await setDebounceInterval(30); // fire at most once per 30 s per beacon
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### `clearDebounceCache()`
|
|
248
|
+
|
|
249
|
+
Resets cooldown state for all beacons, allowing them to fire again immediately.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
await clearDebounceCache();
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### `getDebounceStatus()`
|
|
256
|
+
|
|
257
|
+
Returns the current cooldown state for all tracked beacons.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
const status = await getDebounceStatus();
|
|
261
|
+
console.log(status);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### Debug Helpers
|
|
267
|
+
|
|
268
|
+
#### `getDebugLogs()`
|
|
269
|
+
|
|
270
|
+
Reads the on-device debug log file.
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
const logs = await getDebugLogs();
|
|
274
|
+
console.log(logs);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### `clearDebugLogs()`
|
|
278
|
+
|
|
279
|
+
Deletes the on-device debug log file.
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
await clearDebugLogs();
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## TypeScript Types
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
import type {
|
|
291
|
+
BeaconData,
|
|
292
|
+
BeaconRangedEvent,
|
|
293
|
+
BeaconRegionEvent,
|
|
294
|
+
SpotnySdkConfig,
|
|
295
|
+
} from 'spotny-sdk';
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Platform Notes
|
|
301
|
+
|
|
302
|
+
| Feature | iOS | Android |
|
|
303
|
+
|--------------------------|-----|---------|
|
|
304
|
+
| Region monitoring | ✅ | ✅ |
|
|
305
|
+
| Background scanning | ✅ | ✅ |
|
|
306
|
+
| Terminated-state wakeup | ✅ | ✅ |
|
|
307
|
+
| Notification permissions | ✅ | – |
|
|
308
|
+
|
|
309
|
+
---
|
|
24
310
|
|
|
25
311
|
## Contributing
|
|
26
312
|
|
|
@@ -31,7 +317,3 @@ const result = multiply(3, 7);
|
|
|
31
317
|
## License
|
|
32
318
|
|
|
33
319
|
MIT
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|