expo-beacon 0.5.3 → 0.5.5
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 +35 -21
- package/package.json +1 -1
|
@@ -251,10 +251,12 @@ public class ExpoBeaconModule: Module {
|
|
|
251
251
|
|
|
252
252
|
var eddystones = self.loadPairedEddystonesRaw()
|
|
253
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.
|
|
254
256
|
eddystones.append([
|
|
255
257
|
"identifier": identifier,
|
|
256
|
-
"namespace": namespace,
|
|
257
|
-
"instance": instance
|
|
258
|
+
"namespace": namespace.lowercased(),
|
|
259
|
+
"instance": instance.lowercased()
|
|
258
260
|
])
|
|
259
261
|
self.defaults.set(eddystones, forKey: PAIRED_EDDYSTONES_KEY)
|
|
260
262
|
self.cachedPairedEddystones = nil
|
|
@@ -307,11 +309,17 @@ public class ExpoBeaconModule: Module {
|
|
|
307
309
|
self.defaults.removeObject(forKey: EXIT_DISTANCE_KEY)
|
|
308
310
|
}
|
|
309
311
|
self.defaults.set(true, forKey: IS_MONITORING_KEY)
|
|
310
|
-
self.requestLocationPermission
|
|
312
|
+
self.requestLocationPermission { granted in
|
|
311
313
|
guard granted else {
|
|
312
|
-
promise.reject("PERMISSION_DENIED", "
|
|
314
|
+
promise.reject("PERMISSION_DENIED", "Location permission required for monitoring")
|
|
313
315
|
return
|
|
314
316
|
}
|
|
317
|
+
// Request Always authorization non-blockingly for background support.
|
|
318
|
+
// On iOS 13+ requestAlwaysAuthorization() from WhenInUse may be a
|
|
319
|
+
// no-op if the user already made their choice — don't block on it.
|
|
320
|
+
if self.locationManager.authorizationStatus != .authorizedAlways {
|
|
321
|
+
self.locationManager.requestAlwaysAuthorization()
|
|
322
|
+
}
|
|
315
323
|
self.requestNotificationPermission()
|
|
316
324
|
self.startRegionMonitoring()
|
|
317
325
|
promise.resolve(nil)
|
|
@@ -662,27 +670,14 @@ public class ExpoBeaconModule: Module {
|
|
|
662
670
|
guard let identifier = paired["identifier"] as? String,
|
|
663
671
|
let pns = paired["namespace"] as? String,
|
|
664
672
|
let pinst = paired["instance"] as? String,
|
|
665
|
-
pns == ns && pinst == inst else { continue }
|
|
673
|
+
pns.lowercased() == ns && pinst.lowercased() == inst else { continue }
|
|
666
674
|
|
|
667
675
|
eddystoneLatestSeen[identifier] = Date()
|
|
668
676
|
eddystoneMissCounters[identifier] = 0
|
|
669
677
|
|
|
670
|
-
//
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
now.timeIntervalSince(lastEmit) < DISTANCE_EVENT_THROTTLE_INTERVAL {
|
|
674
|
-
break
|
|
675
|
-
}
|
|
676
|
-
eddystoneLastDistanceEmit[identifier] = now
|
|
677
|
-
|
|
678
|
-
sendEvent("onEddystoneDistance", [
|
|
679
|
-
"identifier": identifier,
|
|
680
|
-
"namespace": ns,
|
|
681
|
-
"instance": inst,
|
|
682
|
-
"distance": distance
|
|
683
|
-
])
|
|
684
|
-
|
|
685
|
-
// Distance-driven enter/exit with hysteresis
|
|
678
|
+
// Distance-driven enter/exit with hysteresis — evaluated on every
|
|
679
|
+
// BLE callback (not throttled) so the hysteresis counters advance
|
|
680
|
+
// reliably regardless of advertisement rate.
|
|
686
681
|
let maxDist = self.defaults.object(forKey: MAX_DISTANCE_KEY) as? Double
|
|
687
682
|
let exitDist = self.defaults.object(forKey: EXIT_DISTANCE_KEY) as? Double
|
|
688
683
|
let action = evaluateDistanceHysteresis(
|
|
@@ -716,6 +711,22 @@ public class ExpoBeaconModule: Module {
|
|
|
716
711
|
case .none:
|
|
717
712
|
break
|
|
718
713
|
}
|
|
714
|
+
|
|
715
|
+
// Throttle distance events — enter/exit above is evaluated on every
|
|
716
|
+
// callback, but distance events are rate-limited to avoid flooding JS.
|
|
717
|
+
let now = Date()
|
|
718
|
+
if let lastEmit = eddystoneLastDistanceEmit[identifier],
|
|
719
|
+
now.timeIntervalSince(lastEmit) < DISTANCE_EVENT_THROTTLE_INTERVAL {
|
|
720
|
+
break
|
|
721
|
+
}
|
|
722
|
+
eddystoneLastDistanceEmit[identifier] = now
|
|
723
|
+
|
|
724
|
+
sendEvent("onEddystoneDistance", [
|
|
725
|
+
"identifier": identifier,
|
|
726
|
+
"namespace": ns,
|
|
727
|
+
"instance": inst,
|
|
728
|
+
"distance": distance
|
|
729
|
+
])
|
|
719
730
|
break
|
|
720
731
|
}
|
|
721
732
|
}
|
|
@@ -1213,9 +1224,12 @@ private class BluetoothDelegate: NSObject, CBCentralManagerDelegate {
|
|
|
1213
1224
|
case .poweredOn:
|
|
1214
1225
|
module?.ensureBleScanRunning()
|
|
1215
1226
|
case .unauthorized:
|
|
1227
|
+
print("[ExpoBeacon] Bluetooth authorization denied — Eddystone scanning/monitoring unavailable. " +
|
|
1228
|
+
"Ensure NSBluetoothAlwaysUsageDescription is set in Info.plist.")
|
|
1216
1229
|
module?.eddystoneScanPromise?.reject("BLUETOOTH_UNAUTHORIZED", "Bluetooth permission denied")
|
|
1217
1230
|
module?.eddystoneScanPromise = nil
|
|
1218
1231
|
case .poweredOff:
|
|
1232
|
+
print("[ExpoBeacon] Bluetooth is powered off — Eddystone scanning/monitoring unavailable.")
|
|
1219
1233
|
module?.eddystoneScanPromise?.reject("BLUETOOTH_OFF", "Bluetooth is powered off")
|
|
1220
1234
|
module?.eddystoneScanPromise = nil
|
|
1221
1235
|
default:
|