expo-beacon 0.5.2 → 0.5.4
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/ios/ExpoBeaconModule.swift +29 -22
- package/package.json +1 -1
|
@@ -242,20 +242,21 @@ public class ExpoBeaconModule: Module {
|
|
|
242
242
|
// MARK: - Eddystone Pair
|
|
243
243
|
|
|
244
244
|
Function("pairEddystone") { (identifier: String, namespace: String, instance: String) -> Void in
|
|
245
|
-
|
|
246
|
-
guard namespace.count == 20, namespace.wholeMatch(of: hexPattern) != nil else {
|
|
245
|
+
guard namespace.count == 20, namespace.range(of: "^[0-9a-fA-F]+$", options: .regularExpression) != nil else {
|
|
247
246
|
throw Exception(name: "INVALID_NAMESPACE", description: "Namespace must be 20 hex characters, got: \(namespace)")
|
|
248
247
|
}
|
|
249
|
-
guard instance.count == 12, instance.
|
|
248
|
+
guard instance.count == 12, instance.range(of: "^[0-9a-fA-F]+$", options: .regularExpression) != nil else {
|
|
250
249
|
throw Exception(name: "INVALID_INSTANCE", description: "Instance must be 12 hex characters, got: \(instance)")
|
|
251
250
|
}
|
|
252
251
|
|
|
253
252
|
var eddystones = self.loadPairedEddystonesRaw()
|
|
254
253
|
eddystones.removeAll { ($0["identifier"] as? String) == identifier }
|
|
254
|
+
// Normalize hex to lowercase — parseEddystoneFrame produces lowercase,
|
|
255
|
+
// so stored values must match for monitoring comparisons.
|
|
255
256
|
eddystones.append([
|
|
256
257
|
"identifier": identifier,
|
|
257
|
-
"namespace": namespace,
|
|
258
|
-
"instance": instance
|
|
258
|
+
"namespace": namespace.lowercased(),
|
|
259
|
+
"instance": instance.lowercased()
|
|
259
260
|
])
|
|
260
261
|
self.defaults.set(eddystones, forKey: PAIRED_EDDYSTONES_KEY)
|
|
261
262
|
self.cachedPairedEddystones = nil
|
|
@@ -663,27 +664,14 @@ public class ExpoBeaconModule: Module {
|
|
|
663
664
|
guard let identifier = paired["identifier"] as? String,
|
|
664
665
|
let pns = paired["namespace"] as? String,
|
|
665
666
|
let pinst = paired["instance"] as? String,
|
|
666
|
-
pns == ns && pinst == inst else { continue }
|
|
667
|
+
pns.lowercased() == ns && pinst.lowercased() == inst else { continue }
|
|
667
668
|
|
|
668
669
|
eddystoneLatestSeen[identifier] = Date()
|
|
669
670
|
eddystoneMissCounters[identifier] = 0
|
|
670
671
|
|
|
671
|
-
//
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
now.timeIntervalSince(lastEmit) < DISTANCE_EVENT_THROTTLE_INTERVAL {
|
|
675
|
-
break
|
|
676
|
-
}
|
|
677
|
-
eddystoneLastDistanceEmit[identifier] = now
|
|
678
|
-
|
|
679
|
-
sendEvent("onEddystoneDistance", [
|
|
680
|
-
"identifier": identifier,
|
|
681
|
-
"namespace": ns,
|
|
682
|
-
"instance": inst,
|
|
683
|
-
"distance": distance
|
|
684
|
-
])
|
|
685
|
-
|
|
686
|
-
// Distance-driven enter/exit with hysteresis
|
|
672
|
+
// Distance-driven enter/exit with hysteresis — evaluated on every
|
|
673
|
+
// BLE callback (not throttled) so the hysteresis counters advance
|
|
674
|
+
// reliably regardless of advertisement rate.
|
|
687
675
|
let maxDist = self.defaults.object(forKey: MAX_DISTANCE_KEY) as? Double
|
|
688
676
|
let exitDist = self.defaults.object(forKey: EXIT_DISTANCE_KEY) as? Double
|
|
689
677
|
let action = evaluateDistanceHysteresis(
|
|
@@ -717,6 +705,22 @@ public class ExpoBeaconModule: Module {
|
|
|
717
705
|
case .none:
|
|
718
706
|
break
|
|
719
707
|
}
|
|
708
|
+
|
|
709
|
+
// Throttle distance events — enter/exit above is evaluated on every
|
|
710
|
+
// callback, but distance events are rate-limited to avoid flooding JS.
|
|
711
|
+
let now = Date()
|
|
712
|
+
if let lastEmit = eddystoneLastDistanceEmit[identifier],
|
|
713
|
+
now.timeIntervalSince(lastEmit) < DISTANCE_EVENT_THROTTLE_INTERVAL {
|
|
714
|
+
break
|
|
715
|
+
}
|
|
716
|
+
eddystoneLastDistanceEmit[identifier] = now
|
|
717
|
+
|
|
718
|
+
sendEvent("onEddystoneDistance", [
|
|
719
|
+
"identifier": identifier,
|
|
720
|
+
"namespace": ns,
|
|
721
|
+
"instance": inst,
|
|
722
|
+
"distance": distance
|
|
723
|
+
])
|
|
720
724
|
break
|
|
721
725
|
}
|
|
722
726
|
}
|
|
@@ -1214,9 +1218,12 @@ private class BluetoothDelegate: NSObject, CBCentralManagerDelegate {
|
|
|
1214
1218
|
case .poweredOn:
|
|
1215
1219
|
module?.ensureBleScanRunning()
|
|
1216
1220
|
case .unauthorized:
|
|
1221
|
+
print("[ExpoBeacon] Bluetooth authorization denied — Eddystone scanning/monitoring unavailable. " +
|
|
1222
|
+
"Ensure NSBluetoothAlwaysUsageDescription is set in Info.plist.")
|
|
1217
1223
|
module?.eddystoneScanPromise?.reject("BLUETOOTH_UNAUTHORIZED", "Bluetooth permission denied")
|
|
1218
1224
|
module?.eddystoneScanPromise = nil
|
|
1219
1225
|
case .poweredOff:
|
|
1226
|
+
print("[ExpoBeacon] Bluetooth is powered off — Eddystone scanning/monitoring unavailable.")
|
|
1220
1227
|
module?.eddystoneScanPromise?.reject("BLUETOOTH_OFF", "Bluetooth is powered off")
|
|
1221
1228
|
module?.eddystoneScanPromise = nil
|
|
1222
1229
|
default:
|