expo-beacon 0.5.0 → 0.5.2
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 +4 -1
- package/android/src/main/java/expo/modules/beacon/BeaconForegroundService.kt +20 -4
- package/android/src/main/java/expo/modules/beacon/ExpoBeaconModule.kt +4 -0
- package/build/ExpoBeacon.types.d.ts +9 -0
- package/build/ExpoBeacon.types.d.ts.map +1 -1
- package/build/ExpoBeacon.types.js.map +1 -1
- package/ios/ExpoBeaconModule.swift +31 -3
- package/package.json +1 -1
- package/src/ExpoBeacon.types.ts +9 -0
package/README.md
CHANGED
|
@@ -832,6 +832,7 @@ Accepts a `MonitoringOptions` object, a plain `number` (shorthand for `maxDistan
|
|
|
832
832
|
| Property | Type | Default | Description |
|
|
833
833
|
|---|---|---|---|
|
|
834
834
|
| `maxDistance` | `number` | `undefined` | Distance threshold in metres. `onBeaconEnter` / `onEddystoneEnter` only fires when measured distance ≤ this value. `onBeaconExit` / `onEddystoneExit` always fires. Omit to disable filtering. |
|
|
835
|
+
| `exitDistance` | `number` | `maxDistance + min(maxDistance × 0.5, 2.5)` | Distance in metres at which exit events fire. Must be ≥ `maxDistance`. Creates a hysteresis band between enter and exit thresholds to prevent rapid toggling near the boundary. Only used when `maxDistance` is set. |
|
|
835
836
|
| `notifications` | `NotificationConfig` | `undefined` | Notification overrides for this session (persisted). |
|
|
836
837
|
|
|
837
838
|
**What happens on each platform**:
|
|
@@ -847,9 +848,10 @@ Accepts a `MonitoringOptions` object, a plain `number` (shorthand for `maxDistan
|
|
|
847
848
|
// Shorthand — just a distance threshold
|
|
848
849
|
await ExpoBeacon.startMonitoring(5);
|
|
849
850
|
|
|
850
|
-
// Full options
|
|
851
|
+
// Full options with custom exit threshold
|
|
851
852
|
await ExpoBeacon.startMonitoring({
|
|
852
853
|
maxDistance: 10,
|
|
854
|
+
exitDistance: 15, // Exit fires when distance exceeds 15m
|
|
853
855
|
notifications: {
|
|
854
856
|
beaconEvents: {
|
|
855
857
|
enterTitle: "Welcome!",
|
|
@@ -1181,6 +1183,7 @@ Passed to `startMonitoring()`.
|
|
|
1181
1183
|
```ts
|
|
1182
1184
|
type MonitoringOptions = {
|
|
1183
1185
|
maxDistance?: number;
|
|
1186
|
+
exitDistance?: number;
|
|
1184
1187
|
notifications?: NotificationConfig;
|
|
1185
1188
|
};
|
|
1186
1189
|
```
|
|
@@ -31,6 +31,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
31
31
|
|
|
32
32
|
// Distance filtering
|
|
33
33
|
@Volatile private var maxDistance: Double? = null
|
|
34
|
+
@Volatile private var exitDistance: Double? = null
|
|
34
35
|
private val rangingRegions = java.util.concurrent.CopyOnWriteArraySet<Region>()
|
|
35
36
|
private val enteredRegions = java.util.concurrent.CopyOnWriteArraySet<String>()
|
|
36
37
|
|
|
@@ -101,9 +102,10 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
override fun onBeaconServiceConnect() {
|
|
104
|
-
// Read max distance from options prefs
|
|
105
|
+
// Read max distance and exit distance from options prefs
|
|
105
106
|
val optPrefs = getSharedPreferences(MONITORING_OPTIONS_PREFS, Context.MODE_PRIVATE)
|
|
106
107
|
maxDistance = optPrefs.getString("max_distance", null)?.toDoubleOrNull()
|
|
108
|
+
exitDistance = optPrefs.getString("exit_distance", null)?.toDoubleOrNull()
|
|
107
109
|
|
|
108
110
|
beaconManager.addMonitorNotifier(monitorNotifier)
|
|
109
111
|
beaconManager.addRangeNotifier(rangeNotifier)
|
|
@@ -296,6 +298,15 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
296
298
|
|
|
297
299
|
private enum class HysteresisAction { NONE, ENTER, EXIT }
|
|
298
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Computes the effective exit distance from maxDistance and an optional explicit exitDistance.
|
|
303
|
+
* Default: maxDistance + min(maxDistance × 0.5, 2.5).
|
|
304
|
+
*/
|
|
305
|
+
private fun effectiveExitDistance(maxDist: Double): Double {
|
|
306
|
+
exitDistance?.let { return it }
|
|
307
|
+
return maxDist + minOf(maxDist * 0.5, 2.5)
|
|
308
|
+
}
|
|
309
|
+
|
|
299
310
|
/**
|
|
300
311
|
* Evaluate distance-based enter/exit with hysteresis counters.
|
|
301
312
|
* Must be called within synchronized(distanceLock).
|
|
@@ -306,8 +317,9 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
306
317
|
distance: Double,
|
|
307
318
|
maxDist: Double
|
|
308
319
|
): HysteresisAction {
|
|
320
|
+
val exitDist = effectiveExitDistance(maxDist)
|
|
309
321
|
if (distance <= maxDist) {
|
|
310
|
-
// Inside threshold
|
|
322
|
+
// Inside enter threshold
|
|
311
323
|
exitCounters[regionId] = 0
|
|
312
324
|
val count = (enterCounters[regionId] ?: 0) + 1
|
|
313
325
|
enterCounters[regionId] = count
|
|
@@ -315,8 +327,8 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
315
327
|
enterCounters[regionId] = 0
|
|
316
328
|
return HysteresisAction.ENTER
|
|
317
329
|
}
|
|
318
|
-
} else {
|
|
319
|
-
// Outside threshold
|
|
330
|
+
} else if (distance > exitDist) {
|
|
331
|
+
// Outside exit threshold
|
|
320
332
|
enterCounters[regionId] = 0
|
|
321
333
|
val count = (exitCounters[regionId] ?: 0) + 1
|
|
322
334
|
exitCounters[regionId] = count
|
|
@@ -324,6 +336,10 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
324
336
|
exitCounters[regionId] = 0
|
|
325
337
|
return HysteresisAction.EXIT
|
|
326
338
|
}
|
|
339
|
+
} else {
|
|
340
|
+
// In the hysteresis band (maxDist < distance <= exitDist) — do nothing
|
|
341
|
+
enterCounters[regionId] = 0
|
|
342
|
+
exitCounters[regionId] = 0
|
|
327
343
|
}
|
|
328
344
|
return HysteresisAction.NONE
|
|
329
345
|
}
|
|
@@ -264,12 +264,14 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
264
264
|
return@AsyncFunction
|
|
265
265
|
}
|
|
266
266
|
var maxDistance: Double? = null
|
|
267
|
+
var exitDistance: Double? = null
|
|
267
268
|
when (options) {
|
|
268
269
|
is Double -> maxDistance = options
|
|
269
270
|
is Map<*, *> -> {
|
|
270
271
|
@Suppress("UNCHECKED_CAST")
|
|
271
272
|
val map = options as Map<String, Any?>
|
|
272
273
|
maxDistance = (map["maxDistance"] as? Number)?.toDouble()
|
|
274
|
+
exitDistance = (map["exitDistance"] as? Number)?.toDouble()
|
|
273
275
|
val notifications = map["notifications"]
|
|
274
276
|
if (notifications is Map<*, *>) {
|
|
275
277
|
@Suppress("UNCHECKED_CAST")
|
|
@@ -282,6 +284,8 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
282
284
|
.edit().apply {
|
|
283
285
|
if (maxDistance != null) putString("max_distance", maxDistance.toString())
|
|
284
286
|
else remove("max_distance")
|
|
287
|
+
if (exitDistance != null) putString("exit_distance", exitDistance.toString())
|
|
288
|
+
else remove("exit_distance")
|
|
285
289
|
}.apply()
|
|
286
290
|
// Verify we have the permissions needed for background monitoring
|
|
287
291
|
val hasLocation = ContextCompat.checkSelfPermission(ctx, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
|
@@ -92,6 +92,15 @@ export type MonitoringOptions = {
|
|
|
92
92
|
* Exit events are always emitted when the region is lost.
|
|
93
93
|
*/
|
|
94
94
|
maxDistance?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Distance in metres at which exit events fire (must be ≥ maxDistance).
|
|
97
|
+
* Creates a hysteresis band between enter and exit thresholds to prevent
|
|
98
|
+
* rapid toggling near the boundary.
|
|
99
|
+
*
|
|
100
|
+
* Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.
|
|
101
|
+
* Only used when `maxDistance` is set.
|
|
102
|
+
*/
|
|
103
|
+
exitDistance?: number;
|
|
95
104
|
/** Notification configuration overrides to apply for this monitoring session. */
|
|
96
105
|
notifications?: NotificationConfig;
|
|
97
106
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeacon.types.js","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"","sourcesContent":["/** Raw beacon discovered during a scan. */\r\nexport type BeaconScanResult = {\r\n uuid: string; // iBeacon proximity UUID (uppercase, formatted)\r\n major: number; // iBeacon major value (0–65535)\r\n minor: number; // iBeacon minor value (0–65535)\r\n rssi: number; // Signal strength in dBm (negative number)\r\n distance: number; // Estimated distance in meters\r\n txPower: number; // Calibrated TX power\r\n};\r\n\r\n/**\r\n * A beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedBeacon = {\r\n identifier: string; // User-defined label (e.g. \"lobby-door\")\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n};\r\n\r\n/** Payload for enter/exit region events. */\r\nexport type BeaconRegionEvent = {\r\n identifier: string; // Matches PairedBeacon.identifier\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n};\r\n\r\n/** Payload for periodic distance update events during monitoring. */\r\nexport type BeaconDistanceEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n distance: number;\r\n};\r\n\r\n/** Configuration for beacon enter/exit event notifications. */\r\nexport type BeaconNotificationConfig = {\r\n /** Whether to show enter/exit notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on beacon enter. Default: \"Beacon Entered\". */\r\n enterTitle?: string;\r\n /** Notification title on beacon exit. Default: \"Beacon Exited\". */\r\n exitTitle?: string;\r\n /**\r\n * Notification body template. Supports {identifier} and {event} placeholders.\r\n * Default: \"{identifier} region {event}ed\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android foreground service notification (persistent status bar entry). */\r\nexport type ForegroundServiceConfig = {\r\n /** Title of the persistent notification. Default: \"Beacon Monitoring Active\". */\r\n title?: string;\r\n /** Body text of the persistent notification. Default: \"Monitoring for iBeacons in the background\". */\r\n text?: string;\r\n /** Android drawable resource name for the notification icon. */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel. */\r\nexport type NotificationChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"Beacon Monitoring\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"Used for background iBeacon region monitoring\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'low'.\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Combined notification configuration for all notification types. */\r\nexport type NotificationConfig = {\r\n /** Settings for beacon enter/exit event notifications. */\r\n beaconEvents?: BeaconNotificationConfig;\r\n /** Settings for the persistent foreground service notification (Android only). */\r\n foregroundService?: ForegroundServiceConfig;\r\n /** Settings for the Android notification channel (Android only). */\r\n channel?: NotificationChannelConfig;\r\n};\r\n\r\n/** Options accepted by startMonitoring(). */\r\nexport type MonitoringOptions = {\r\n /**\r\n * Maximum distance in metres for distance-based enter events.\r\n * Exit events are always emitted when the region is lost.\r\n */\r\n maxDistance?: number;\r\n /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Eddystone frame type. */\r\nexport type EddystoneFrameType = \"uid\" | \"url\";\r\n\r\n/** Raw Eddystone beacon discovered during a scan. */\r\nexport type EddystoneScanResult = {\r\n frameType: EddystoneFrameType;\r\n /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */\r\n namespace?: string;\r\n /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */\r\n instance?: string;\r\n /** Decoded URL. Present for URL frames. */\r\n url?: string;\r\n rssi: number;\r\n distance: number;\r\n txPower: number;\r\n};\r\n\r\n/**\r\n * An Eddystone-UID beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedEddystone = {\r\n identifier: string;\r\n /** 10-byte namespace ID as hex string (20 chars). */\r\n namespace: string;\r\n /** 6-byte instance ID as hex string (12 chars). */\r\n instance: string;\r\n};\r\n\r\n/** Payload for Eddystone enter/exit region events. */\r\nexport type EddystoneRegionEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n};\r\n\r\n/** Payload for periodic Eddystone distance update events during monitoring. */\r\nexport type EddystoneDistanceEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n distance: number;\r\n};\r\n\r\n/** Module event map. */\r\nexport type ExpoBeaconModuleEvents = {\r\n onBeaconEnter: (params: BeaconRegionEvent) => void;\r\n onBeaconExit: (params: BeaconRegionEvent) => void;\r\n onBeaconDistance: (params: BeaconDistanceEvent) => void;\r\n /** Fired continuously during a live scan as each iBeacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\r\n /** Fired continuously during a live scan as each Eddystone beacon is detected. */\r\n onEddystoneFound: (params: EddystoneScanResult) => void;\r\n onEddystoneEnter: (params: EddystoneRegionEvent) => void;\r\n onEddystoneExit: (params: EddystoneRegionEvent) => void;\r\n onEddystoneDistance: (params: EddystoneDistanceEvent) => void;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoBeacon.types.js","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"","sourcesContent":["/** Raw beacon discovered during a scan. */\r\nexport type BeaconScanResult = {\r\n uuid: string; // iBeacon proximity UUID (uppercase, formatted)\r\n major: number; // iBeacon major value (0–65535)\r\n minor: number; // iBeacon minor value (0–65535)\r\n rssi: number; // Signal strength in dBm (negative number)\r\n distance: number; // Estimated distance in meters\r\n txPower: number; // Calibrated TX power\r\n};\r\n\r\n/**\r\n * A beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedBeacon = {\r\n identifier: string; // User-defined label (e.g. \"lobby-door\")\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n};\r\n\r\n/** Payload for enter/exit region events. */\r\nexport type BeaconRegionEvent = {\r\n identifier: string; // Matches PairedBeacon.identifier\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n};\r\n\r\n/** Payload for periodic distance update events during monitoring. */\r\nexport type BeaconDistanceEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n distance: number;\r\n};\r\n\r\n/** Configuration for beacon enter/exit event notifications. */\r\nexport type BeaconNotificationConfig = {\r\n /** Whether to show enter/exit notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on beacon enter. Default: \"Beacon Entered\". */\r\n enterTitle?: string;\r\n /** Notification title on beacon exit. Default: \"Beacon Exited\". */\r\n exitTitle?: string;\r\n /**\r\n * Notification body template. Supports {identifier} and {event} placeholders.\r\n * Default: \"{identifier} region {event}ed\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android foreground service notification (persistent status bar entry). */\r\nexport type ForegroundServiceConfig = {\r\n /** Title of the persistent notification. Default: \"Beacon Monitoring Active\". */\r\n title?: string;\r\n /** Body text of the persistent notification. Default: \"Monitoring for iBeacons in the background\". */\r\n text?: string;\r\n /** Android drawable resource name for the notification icon. */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel. */\r\nexport type NotificationChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"Beacon Monitoring\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"Used for background iBeacon region monitoring\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'low'.\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Combined notification configuration for all notification types. */\r\nexport type NotificationConfig = {\r\n /** Settings for beacon enter/exit event notifications. */\r\n beaconEvents?: BeaconNotificationConfig;\r\n /** Settings for the persistent foreground service notification (Android only). */\r\n foregroundService?: ForegroundServiceConfig;\r\n /** Settings for the Android notification channel (Android only). */\r\n channel?: NotificationChannelConfig;\r\n};\r\n\r\n/** Options accepted by startMonitoring(). */\r\nexport type MonitoringOptions = {\r\n /**\r\n * Maximum distance in metres for distance-based enter events.\r\n * Exit events are always emitted when the region is lost.\r\n */\r\n maxDistance?: number;\r\n /**\r\n * Distance in metres at which exit events fire (must be ≥ maxDistance).\r\n * Creates a hysteresis band between enter and exit thresholds to prevent\r\n * rapid toggling near the boundary.\r\n *\r\n * Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.\r\n * Only used when `maxDistance` is set.\r\n */\r\n exitDistance?: number;\r\n /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Eddystone frame type. */\r\nexport type EddystoneFrameType = \"uid\" | \"url\";\r\n\r\n/** Raw Eddystone beacon discovered during a scan. */\r\nexport type EddystoneScanResult = {\r\n frameType: EddystoneFrameType;\r\n /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */\r\n namespace?: string;\r\n /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */\r\n instance?: string;\r\n /** Decoded URL. Present for URL frames. */\r\n url?: string;\r\n rssi: number;\r\n distance: number;\r\n txPower: number;\r\n};\r\n\r\n/**\r\n * An Eddystone-UID beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedEddystone = {\r\n identifier: string;\r\n /** 10-byte namespace ID as hex string (20 chars). */\r\n namespace: string;\r\n /** 6-byte instance ID as hex string (12 chars). */\r\n instance: string;\r\n};\r\n\r\n/** Payload for Eddystone enter/exit region events. */\r\nexport type EddystoneRegionEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n};\r\n\r\n/** Payload for periodic Eddystone distance update events during monitoring. */\r\nexport type EddystoneDistanceEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n distance: number;\r\n};\r\n\r\n/** Module event map. */\r\nexport type ExpoBeaconModuleEvents = {\r\n onBeaconEnter: (params: BeaconRegionEvent) => void;\r\n onBeaconExit: (params: BeaconRegionEvent) => void;\r\n onBeaconDistance: (params: BeaconDistanceEvent) => void;\r\n /** Fired continuously during a live scan as each iBeacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\r\n /** Fired continuously during a live scan as each Eddystone beacon is detected. */\r\n onEddystoneFound: (params: EddystoneScanResult) => void;\r\n onEddystoneEnter: (params: EddystoneRegionEvent) => void;\r\n onEddystoneExit: (params: EddystoneRegionEvent) => void;\r\n onEddystoneDistance: (params: EddystoneDistanceEvent) => void;\r\n};\r\n"]}
|
|
@@ -8,6 +8,7 @@ private let PAIRED_BEACONS_KEY = "expo.beacon.paired"
|
|
|
8
8
|
private let PAIRED_EDDYSTONES_KEY = "expo.beacon.paired_eddystones"
|
|
9
9
|
private let IS_MONITORING_KEY = "expo.beacon.is_monitoring"
|
|
10
10
|
private let MAX_DISTANCE_KEY = "expo.beacon.max_distance"
|
|
11
|
+
private let EXIT_DISTANCE_KEY = "expo.beacon.exit_distance"
|
|
11
12
|
private let NOTIFICATION_CONFIG_KEY = "expo.beacon.notification_config"
|
|
12
13
|
|
|
13
14
|
/// Number of consecutive ranging misses before emitting a distance-based exit event.
|
|
@@ -97,10 +98,12 @@ public class ExpoBeaconModule: Module {
|
|
|
97
98
|
}()
|
|
98
99
|
|
|
99
100
|
public func definition() -> ModuleDefinition {
|
|
100
|
-
migrateUserDefaultsIfNeeded()
|
|
101
|
-
|
|
102
101
|
Name("ExpoBeacon")
|
|
103
102
|
|
|
103
|
+
OnCreate {
|
|
104
|
+
self.migrateUserDefaultsIfNeeded()
|
|
105
|
+
}
|
|
106
|
+
|
|
104
107
|
Events("onBeaconEnter", "onBeaconExit", "onBeaconDistance", "onBeaconFound", "onEddystoneFound", "onEddystoneEnter", "onEddystoneExit", "onEddystoneDistance")
|
|
105
108
|
|
|
106
109
|
// MARK: - Scan
|
|
@@ -282,10 +285,12 @@ public class ExpoBeaconModule: Module {
|
|
|
282
285
|
|
|
283
286
|
AsyncFunction("startMonitoring") { (options: Either<Double, [String: Any]>?, promise: Promise) in
|
|
284
287
|
var maxDistance: Double? = nil
|
|
288
|
+
var exitDistance: Double? = nil
|
|
285
289
|
if let dist: Double = options?.get() {
|
|
286
290
|
maxDistance = dist
|
|
287
291
|
} else if let map: [String: Any] = options?.get() {
|
|
288
292
|
maxDistance = map["maxDistance"] as? Double
|
|
293
|
+
exitDistance = map["exitDistance"] as? Double
|
|
289
294
|
if let notifications = map["notifications"] as? [String: Any],
|
|
290
295
|
let data = try? JSONSerialization.data(withJSONObject: notifications),
|
|
291
296
|
let json = String(data: data, encoding: .utf8) {
|
|
@@ -297,6 +302,11 @@ public class ExpoBeaconModule: Module {
|
|
|
297
302
|
} else {
|
|
298
303
|
self.defaults.removeObject(forKey: MAX_DISTANCE_KEY)
|
|
299
304
|
}
|
|
305
|
+
if let exitDist = exitDistance {
|
|
306
|
+
self.defaults.set(exitDist, forKey: EXIT_DISTANCE_KEY)
|
|
307
|
+
} else {
|
|
308
|
+
self.defaults.removeObject(forKey: EXIT_DISTANCE_KEY)
|
|
309
|
+
}
|
|
300
310
|
self.defaults.set(true, forKey: IS_MONITORING_KEY)
|
|
301
311
|
self.requestLocationPermission(requireAlways: true) { granted in
|
|
302
312
|
guard granted else {
|
|
@@ -312,6 +322,7 @@ public class ExpoBeaconModule: Module {
|
|
|
312
322
|
AsyncFunction("stopMonitoring") { (promise: Promise) in
|
|
313
323
|
self.defaults.set(false, forKey: IS_MONITORING_KEY)
|
|
314
324
|
self.defaults.removeObject(forKey: MAX_DISTANCE_KEY)
|
|
325
|
+
self.defaults.removeObject(forKey: EXIT_DISTANCE_KEY)
|
|
315
326
|
self.stopRegionMonitoring()
|
|
316
327
|
promise.resolve(nil)
|
|
317
328
|
}
|
|
@@ -674,10 +685,12 @@ public class ExpoBeaconModule: Module {
|
|
|
674
685
|
|
|
675
686
|
// Distance-driven enter/exit with hysteresis
|
|
676
687
|
let maxDist = self.defaults.object(forKey: MAX_DISTANCE_KEY) as? Double
|
|
688
|
+
let exitDist = self.defaults.object(forKey: EXIT_DISTANCE_KEY) as? Double
|
|
677
689
|
let action = evaluateDistanceHysteresis(
|
|
678
690
|
identifier: identifier,
|
|
679
691
|
distance: distance,
|
|
680
692
|
maxDistance: maxDist,
|
|
693
|
+
exitDistance: exitDist,
|
|
681
694
|
entered: &eddystoneEnteredRegions,
|
|
682
695
|
enterCtrs: &eddystoneEnterCounters,
|
|
683
696
|
exitCtrs: &eddystoneExitCounters
|
|
@@ -921,17 +934,26 @@ public class ExpoBeaconModule: Module {
|
|
|
921
934
|
case none, enter, exit
|
|
922
935
|
}
|
|
923
936
|
|
|
937
|
+
/// Computes the effective exit distance from maxDistance and an optional explicit exitDistance.
|
|
938
|
+
/// Default: maxDistance + min(maxDistance × 0.5, 2.5).
|
|
939
|
+
private static func effectiveExitDistance(maxDistance: Double, exitDistance: Double?) -> Double {
|
|
940
|
+
if let explicit = exitDistance { return explicit }
|
|
941
|
+
return maxDistance + min(maxDistance * 0.5, 2.5)
|
|
942
|
+
}
|
|
943
|
+
|
|
924
944
|
/// Shared distance-based enter/exit evaluation with hysteresis.
|
|
925
945
|
/// Used by both iBeacon (handleDidRange) and Eddystone (handleEddystoneDiscovery) paths.
|
|
926
946
|
private func evaluateDistanceHysteresis(
|
|
927
947
|
identifier: String,
|
|
928
948
|
distance: Double,
|
|
929
949
|
maxDistance: Double?,
|
|
950
|
+
exitDistance: Double?,
|
|
930
951
|
entered: inout Set<String>,
|
|
931
952
|
enterCtrs: inout [String: Int],
|
|
932
953
|
exitCtrs: inout [String: Int]
|
|
933
954
|
) -> HysteresisAction {
|
|
934
955
|
if let maxDist = maxDistance {
|
|
956
|
+
let exitDist = Self.effectiveExitDistance(maxDistance: maxDist, exitDistance: exitDistance)
|
|
935
957
|
if distance <= maxDist {
|
|
936
958
|
exitCtrs[identifier] = 0
|
|
937
959
|
enterCtrs[identifier] = (enterCtrs[identifier] ?? 0) + 1
|
|
@@ -940,7 +962,7 @@ public class ExpoBeaconModule: Module {
|
|
|
940
962
|
enterCtrs[identifier] = 0
|
|
941
963
|
return .enter
|
|
942
964
|
}
|
|
943
|
-
} else {
|
|
965
|
+
} else if distance > exitDist {
|
|
944
966
|
enterCtrs[identifier] = 0
|
|
945
967
|
exitCtrs[identifier] = (exitCtrs[identifier] ?? 0) + 1
|
|
946
968
|
if entered.contains(identifier) && (exitCtrs[identifier] ?? 0) >= HYSTERESIS_COUNT {
|
|
@@ -948,6 +970,10 @@ public class ExpoBeaconModule: Module {
|
|
|
948
970
|
exitCtrs[identifier] = 0
|
|
949
971
|
return .exit
|
|
950
972
|
}
|
|
973
|
+
} else {
|
|
974
|
+
// In the hysteresis band (maxDist < distance <= exitDist) — do nothing
|
|
975
|
+
enterCtrs[identifier] = 0
|
|
976
|
+
exitCtrs[identifier] = 0
|
|
951
977
|
}
|
|
952
978
|
} else {
|
|
953
979
|
enterCtrs[identifier] = (enterCtrs[identifier] ?? 0) + 1
|
|
@@ -1020,10 +1046,12 @@ public class ExpoBeaconModule: Module {
|
|
|
1020
1046
|
|
|
1021
1047
|
// Distance-driven enter/exit synthesis with hysteresis
|
|
1022
1048
|
if let maxDist = self.defaults.object(forKey: MAX_DISTANCE_KEY) as? Double {
|
|
1049
|
+
let exitDist = self.defaults.object(forKey: EXIT_DISTANCE_KEY) as? Double
|
|
1023
1050
|
let action = evaluateDistanceHysteresis(
|
|
1024
1051
|
identifier: identifier,
|
|
1025
1052
|
distance: beacon.accuracy,
|
|
1026
1053
|
maxDistance: maxDist,
|
|
1054
|
+
exitDistance: exitDist,
|
|
1027
1055
|
entered: &enteredRegions,
|
|
1028
1056
|
enterCtrs: &enterCounters,
|
|
1029
1057
|
exitCtrs: &exitCounters
|
package/package.json
CHANGED
package/src/ExpoBeacon.types.ts
CHANGED
|
@@ -100,6 +100,15 @@ export type MonitoringOptions = {
|
|
|
100
100
|
* Exit events are always emitted when the region is lost.
|
|
101
101
|
*/
|
|
102
102
|
maxDistance?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Distance in metres at which exit events fire (must be ≥ maxDistance).
|
|
105
|
+
* Creates a hysteresis band between enter and exit thresholds to prevent
|
|
106
|
+
* rapid toggling near the boundary.
|
|
107
|
+
*
|
|
108
|
+
* Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.
|
|
109
|
+
* Only used when `maxDistance` is set.
|
|
110
|
+
*/
|
|
111
|
+
exitDistance?: number;
|
|
103
112
|
/** Notification configuration overrides to apply for this monitoring session. */
|
|
104
113
|
notifications?: NotificationConfig;
|
|
105
114
|
};
|