@capgo/capacitor-ibeacon 8.1.31 → 8.1.33
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.
|
@@ -44,7 +44,7 @@ import org.altbeacon.beacon.Settings;
|
|
|
44
44
|
)
|
|
45
45
|
public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
46
46
|
|
|
47
|
-
private final String pluginVersion = "8.1.
|
|
47
|
+
private final String pluginVersion = "8.1.33";
|
|
48
48
|
private static final String FOREGROUND_CHANNEL_ID = "beacon_service_channel";
|
|
49
49
|
private static final int FOREGROUND_NOTIFICATION_ID = 456;
|
|
50
50
|
private BeaconManager beaconManager;
|
|
@@ -80,8 +80,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
80
80
|
beaconManager.setForegroundBetweenScanPeriod(0L); // Continuous scanning in foreground
|
|
81
81
|
beaconManager.setForegroundScanPeriod(1100L); // Standard scan period
|
|
82
82
|
|
|
83
|
-
//
|
|
84
|
-
beaconManager.bind(this);
|
|
83
|
+
// bind() is deferred to bindIfNeeded().
|
|
85
84
|
|
|
86
85
|
// Set up monitoring and ranging notifiers
|
|
87
86
|
beaconManager.addMonitorNotifier(
|
|
@@ -144,7 +143,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
144
143
|
|
|
145
144
|
@Override
|
|
146
145
|
public void onBeaconServiceConnect() {
|
|
147
|
-
beaconManagerBound
|
|
146
|
+
// beaconManagerBound is already set synchronously wherever bind() is called.
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
@Override
|
|
@@ -179,6 +178,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
179
178
|
if (enableBackgroundMode != null) {
|
|
180
179
|
setBackgroundModeEnabled(enableBackgroundMode);
|
|
181
180
|
}
|
|
181
|
+
bindIfNeeded();
|
|
182
182
|
Region region = createRegion(identifier, uuid, major, minor);
|
|
183
183
|
monitoredRegions.put(identifier, region);
|
|
184
184
|
beaconManager.startMonitoring(region);
|
|
@@ -227,6 +227,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
227
227
|
if (enableBackgroundMode != null) {
|
|
228
228
|
setBackgroundModeEnabled(enableBackgroundMode);
|
|
229
229
|
}
|
|
230
|
+
bindIfNeeded();
|
|
230
231
|
Region region = createRegion(identifier, uuid, major, minor);
|
|
231
232
|
rangedRegions.put(identifier, region);
|
|
232
233
|
beaconManager.startRangingBeacons(region);
|
|
@@ -567,8 +568,17 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
567
568
|
@PluginMethod
|
|
568
569
|
public void enableBackgroundMode(PluginCall call) {
|
|
569
570
|
Boolean enabled = call.getBoolean("enabled", true);
|
|
570
|
-
|
|
571
|
-
|
|
571
|
+
boolean wantBackground = enabled != null && enabled;
|
|
572
|
+
try {
|
|
573
|
+
if (!ensureForegroundServiceMatches(wantBackground)) {
|
|
574
|
+
call.reject("Failed to enable foreground service scanning");
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
setBackgroundModeEnabled(wantBackground);
|
|
578
|
+
call.resolve();
|
|
579
|
+
} catch (Exception e) {
|
|
580
|
+
call.reject("Failed to enable background mode", e);
|
|
581
|
+
}
|
|
572
582
|
}
|
|
573
583
|
|
|
574
584
|
@PluginMethod
|
|
@@ -579,6 +589,9 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
579
589
|
try {
|
|
580
590
|
beaconManager.setBackgroundScanPeriod(scanPeriod);
|
|
581
591
|
beaconManager.setBackgroundBetweenScanPeriod(betweenScanPeriod);
|
|
592
|
+
if (beaconManagerBound) {
|
|
593
|
+
beaconManager.updateScanPeriods();
|
|
594
|
+
}
|
|
582
595
|
call.resolve();
|
|
583
596
|
} catch (Exception e) {
|
|
584
597
|
call.reject("Failed to set background scan period", e);
|
|
@@ -703,6 +716,17 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
703
716
|
}
|
|
704
717
|
}
|
|
705
718
|
|
|
719
|
+
private void bindIfNeeded() {
|
|
720
|
+
ensureForegroundServiceMatches(backgroundModeEnabled);
|
|
721
|
+
if (beaconManagerBound || beaconManager == null) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
// Set before bind() - AltBeacon is synchronously bound inside bind() itself, not only
|
|
725
|
+
// once onBeaconServiceConnect() fires.
|
|
726
|
+
beaconManagerBound = true;
|
|
727
|
+
beaconManager.bind(this);
|
|
728
|
+
}
|
|
729
|
+
|
|
706
730
|
private void setBackgroundModeEnabled(boolean enabled) {
|
|
707
731
|
backgroundModeEnabled = enabled;
|
|
708
732
|
applyBackgroundMode(enabled);
|
|
@@ -712,16 +736,43 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
|
|
|
712
736
|
if (beaconManager == null) {
|
|
713
737
|
return;
|
|
714
738
|
}
|
|
739
|
+
beaconManager.setBackgroundMode(enabled && isInBackground);
|
|
740
|
+
}
|
|
715
741
|
|
|
716
|
-
|
|
742
|
+
// Covers both a fresh bind and a later call (e.g. a per-region enableBackgroundMode option)
|
|
743
|
+
// that raises the requirement while already bound.
|
|
744
|
+
private boolean ensureForegroundServiceMatches(boolean wantForegroundService) {
|
|
745
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || wantForegroundService == foregroundServiceEnabled) {
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
return reconfigureForegroundService(wantForegroundService);
|
|
749
|
+
}
|
|
717
750
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
751
|
+
// enableForegroundServiceScanning()/disableForegroundServiceScanning() may only be called
|
|
752
|
+
// while unbound. Re-registers any regions that were actively monitored/ranged before the cycle.
|
|
753
|
+
private boolean reconfigureForegroundService(boolean wantForegroundService) {
|
|
754
|
+
boolean wasBound = beaconManagerBound;
|
|
755
|
+
if (wasBound) {
|
|
756
|
+
beaconManager.unbind(this);
|
|
757
|
+
beaconManagerBound = false;
|
|
758
|
+
}
|
|
759
|
+
boolean success = true;
|
|
760
|
+
if (wantForegroundService) {
|
|
761
|
+
success = enableForegroundServiceIfNeeded();
|
|
721
762
|
} else {
|
|
722
763
|
disableForegroundServiceIfNeeded();
|
|
723
|
-
beaconManager.setBackgroundMode(false);
|
|
724
764
|
}
|
|
765
|
+
if (wasBound) {
|
|
766
|
+
beaconManagerBound = true;
|
|
767
|
+
beaconManager.bind(this);
|
|
768
|
+
for (Region region : monitoredRegions.values()) {
|
|
769
|
+
beaconManager.startMonitoring(region);
|
|
770
|
+
}
|
|
771
|
+
for (Region region : rangedRegions.values()) {
|
|
772
|
+
beaconManager.startRangingBeacons(region);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return success;
|
|
725
776
|
}
|
|
726
777
|
|
|
727
778
|
private boolean enableForegroundServiceIfNeeded() {
|
|
@@ -8,18 +8,44 @@ public class CapacitorIbeacon: NSObject, CLLocationManagerDelegate, CBPeripheral
|
|
|
8
8
|
private weak var plugin: CapacitorIbeaconPlugin?
|
|
9
9
|
private var monitoredRegions: [String: CLBeaconRegion] = [:]
|
|
10
10
|
private var rangedRegions: [String: CLBeaconRegion] = [:]
|
|
11
|
+
private var peripheralManagerReadyCallbacks: [(CBPeripheralManager) -> Void] = []
|
|
12
|
+
private let peripheralManagerStateTimeout: TimeInterval = 3.0
|
|
11
13
|
|
|
12
14
|
override public init() {
|
|
13
15
|
super.init()
|
|
14
16
|
locationManager = CLLocationManager()
|
|
15
17
|
locationManager.delegate = self
|
|
16
|
-
peripheralManager
|
|
18
|
+
// peripheralManager intentionally not constructed here - see withReadyPeripheralManager().
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
public func setPlugin(_ plugin: CapacitorIbeaconPlugin) {
|
|
20
22
|
self.plugin = plugin
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
// Merely instantiating CBPeripheralManager triggers the Bluetooth permission prompt, so
|
|
26
|
+
// construction is deferred to here rather than init(). Its state also starts .unknown and
|
|
27
|
+
// only settles asynchronously via peripheralManagerDidUpdateState() below, so `body` waits
|
|
28
|
+
// for that instead of seeing a stale .unknown - with a timeout in case it never settles.
|
|
29
|
+
private func withReadyPeripheralManager(_ body: @escaping (CBPeripheralManager) -> Void) {
|
|
30
|
+
if peripheralManager == nil {
|
|
31
|
+
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if peripheralManager.state != .unknown {
|
|
35
|
+
body(peripheralManager)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
peripheralManagerReadyCallbacks.append(body)
|
|
40
|
+
|
|
41
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + peripheralManagerStateTimeout) { [weak self] in
|
|
42
|
+
guard let self = self, !self.peripheralManagerReadyCallbacks.isEmpty else { return }
|
|
43
|
+
let callbacks = self.peripheralManagerReadyCallbacks
|
|
44
|
+
self.peripheralManagerReadyCallbacks.removeAll()
|
|
45
|
+
callbacks.forEach { $0(self.peripheralManager) }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
23
49
|
public func startMonitoringForRegion(identifier: String, uuid: String, major: Int?, minor: Int?, completion: @escaping (Result<Void, Error>) -> Void) {
|
|
24
50
|
guard let beaconUUID = UUID(uuidString: uuid) else {
|
|
25
51
|
completion(.failure(NSError(domain: "CapacitorIbeacon", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid UUID"])))
|
|
@@ -90,17 +116,27 @@ public class CapacitorIbeacon: NSObject, CLLocationManagerDelegate, CBPeripheral
|
|
|
90
116
|
|
|
91
117
|
let beaconRegion = CLBeaconRegion(uuid: beaconUUID, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: identifier)
|
|
92
118
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
119
|
+
withReadyPeripheralManager { manager in
|
|
120
|
+
guard manager.state == .poweredOn else {
|
|
121
|
+
let error = NSError(domain: "CapacitorIbeacon", code: -2, userInfo: [NSLocalizedDescriptionKey: "Bluetooth is not powered on"])
|
|
122
|
+
completion(.failure(error))
|
|
123
|
+
return
|
|
124
|
+
}
|
|
98
125
|
|
|
99
|
-
|
|
126
|
+
if let power = measuredPower {
|
|
127
|
+
manager.startAdvertising(beaconRegion.peripheralData(withMeasuredPower: NSNumber(value: power)) as? [String: Any])
|
|
128
|
+
} else {
|
|
129
|
+
manager.startAdvertising(beaconRegion.peripheralData(withMeasuredPower: nil) as? [String: Any])
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
completion(.success(()))
|
|
133
|
+
}
|
|
100
134
|
}
|
|
101
135
|
|
|
102
136
|
public func stopAdvertising() {
|
|
103
|
-
|
|
137
|
+
// Not ensurePeripheralManager(): stopping something that was never started shouldn't
|
|
138
|
+
// newly construct (and trigger a permission prompt for) a manager that doesn't exist yet.
|
|
139
|
+
peripheralManager?.stopAdvertising()
|
|
104
140
|
}
|
|
105
141
|
|
|
106
142
|
public func requestWhenInUseAuthorization() {
|
|
@@ -129,8 +165,10 @@ public class CapacitorIbeacon: NSObject, CLLocationManagerDelegate, CBPeripheral
|
|
|
129
165
|
}
|
|
130
166
|
}
|
|
131
167
|
|
|
132
|
-
public func isBluetoothEnabled() ->
|
|
133
|
-
|
|
168
|
+
public func isBluetoothEnabled(completion: @escaping (Bool) -> Void) {
|
|
169
|
+
withReadyPeripheralManager { manager in
|
|
170
|
+
completion(manager.state == .poweredOn)
|
|
171
|
+
}
|
|
134
172
|
}
|
|
135
173
|
|
|
136
174
|
public func isRangingAvailable() -> Bool {
|
|
@@ -229,6 +267,11 @@ public class CapacitorIbeacon: NSObject, CLLocationManagerDelegate, CBPeripheral
|
|
|
229
267
|
// MARK: - CBPeripheralManagerDelegate
|
|
230
268
|
|
|
231
269
|
public func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
|
|
232
|
-
|
|
270
|
+
guard !peripheralManagerReadyCallbacks.isEmpty else {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
let callbacks = peripheralManagerReadyCallbacks
|
|
274
|
+
peripheralManagerReadyCallbacks.removeAll()
|
|
275
|
+
callbacks.forEach { $0(peripheral) }
|
|
233
276
|
}
|
|
234
277
|
}
|
|
@@ -4,7 +4,7 @@ import CoreLocation
|
|
|
4
4
|
|
|
5
5
|
@objc(CapacitorIbeaconPlugin)
|
|
6
6
|
public class CapacitorIbeaconPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
7
|
-
private let pluginVersion: String = "8.1.
|
|
7
|
+
private let pluginVersion: String = "8.1.33"
|
|
8
8
|
public let identifier = "CapacitorIbeaconPlugin"
|
|
9
9
|
public let jsName = "CapacitorIbeacon"
|
|
10
10
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -144,8 +144,9 @@ public class CapacitorIbeaconPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
@objc func isBluetoothEnabled(_ call: CAPPluginCall) {
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
implementation.isBluetoothEnabled { enabled in
|
|
148
|
+
call.resolve(["enabled": enabled])
|
|
149
|
+
}
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
@objc func isRangingAvailable(_ call: CAPPluginCall) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-ibeacon",
|
|
3
|
-
"version": "8.1.
|
|
3
|
+
"version": "8.1.33",
|
|
4
4
|
"description": "iBeacon plugin for Capacitor - proximity detection and beacon region monitoring",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
"prepublishOnly": "bun run build",
|
|
56
56
|
"check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs",
|
|
57
57
|
"example:install": "cd example-app && bun install --frozen-lockfile",
|
|
58
|
-
"example:build": "bun run build && cd example-app && bun install --frozen-lockfile && bun run build"
|
|
58
|
+
"example:build": "bun run build && cd example-app && bun install --frozen-lockfile && bun run build",
|
|
59
|
+
"changelog:ai": "node scripts/generate-ai-changelog.mjs"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"@capacitor/android": "^8.0.0",
|