@capgo/capacitor-ibeacon 8.1.1 → 8.1.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 CHANGED
@@ -194,6 +194,34 @@ Enable ARMA filtering for distance calculations (Android only).
194
194
  await CapacitorIbeacon.enableARMAFilter({ enabled: true });
195
195
  ```
196
196
 
197
+ ### Android background scanning
198
+
199
+ Android 8+ requires a foreground service to keep Bluetooth scanning alive in the background. You can opt in once and the plugin will automatically
200
+ toggle background scanning when the app moves between foreground and background.
201
+
202
+ ```typescript
203
+ // Enable background scanning globally (Android only)
204
+ await CapacitorIbeacon.enableBackgroundMode({ enabled: true });
205
+
206
+ // Or opt in per call
207
+ await CapacitorIbeacon.startMonitoringForRegion({
208
+ identifier: 'MyBeaconRegion',
209
+ uuid: 'B9407F30-F5F8-466E-AFF9-25556B57FE6D',
210
+ enableBackgroundMode: true,
211
+ });
212
+ ```
213
+
214
+ You can also enable it via Capacitor config:
215
+
216
+ ```typescript
217
+ // capacitor.config.ts
218
+ plugins: {
219
+ CapacitorIbeacon: {
220
+ enableBackgroundMode: true,
221
+ },
222
+ }
223
+ ```
224
+
197
225
  ## Events
198
226
 
199
227
  Listen to beacon events using Capacitor's event system:
@@ -43,11 +43,16 @@ import org.altbeacon.beacon.Region;
43
43
  )
44
44
  public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
45
45
 
46
- private final String pluginVersion = "8.1.1";
46
+ private final String pluginVersion = "8.1.3";
47
+ private static final String FOREGROUND_CHANNEL_ID = "beacon_service_channel";
48
+ private static final int FOREGROUND_NOTIFICATION_ID = 456;
47
49
  private BeaconManager beaconManager;
48
50
  private Map<String, Region> monitoredRegions = new HashMap<>();
49
51
  private Map<String, Region> rangedRegions = new HashMap<>();
50
52
  private boolean beaconManagerBound = false;
53
+ private boolean backgroundModeEnabled = false;
54
+ private boolean foregroundServiceEnabled = false;
55
+ private boolean isInBackground = false;
51
56
 
52
57
  @Override
53
58
  public void load() {
@@ -102,10 +107,16 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
102
107
  }
103
108
  }
104
109
  );
110
+
111
+ Boolean configBackgroundMode = getConfig().getBoolean("enableBackgroundMode", false);
112
+ if (configBackgroundMode != null && configBackgroundMode) {
113
+ backgroundModeEnabled = true;
114
+ }
105
115
  }
106
116
 
107
117
  @Override
108
118
  protected void handleOnDestroy() {
119
+ applyBackgroundMode(false);
109
120
  if (beaconManager != null && beaconManagerBound) {
110
121
  beaconManager.unbind(this);
111
122
  beaconManagerBound = false;
@@ -113,6 +124,20 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
113
124
  super.handleOnDestroy();
114
125
  }
115
126
 
127
+ @Override
128
+ protected void handleOnPause() {
129
+ super.handleOnPause();
130
+ isInBackground = true;
131
+ applyBackgroundMode(backgroundModeEnabled);
132
+ }
133
+
134
+ @Override
135
+ protected void handleOnResume() {
136
+ super.handleOnResume();
137
+ isInBackground = false;
138
+ applyBackgroundMode(backgroundModeEnabled);
139
+ }
140
+
116
141
  @Override
117
142
  public void onBeaconServiceConnect() {
118
143
  beaconManagerBound = true;
@@ -139,6 +164,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
139
164
  String uuid = call.getString("uuid");
140
165
  Integer major = call.getInt("major");
141
166
  Integer minor = call.getInt("minor");
167
+ Boolean enableBackgroundMode = call.getBoolean("enableBackgroundMode");
142
168
 
143
169
  if (identifier == null || uuid == null) {
144
170
  call.reject("Missing required parameters");
@@ -146,6 +172,9 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
146
172
  }
147
173
 
148
174
  try {
175
+ if (enableBackgroundMode != null) {
176
+ setBackgroundModeEnabled(enableBackgroundMode);
177
+ }
149
178
  Region region = createRegion(identifier, uuid, major, minor);
150
179
  monitoredRegions.put(identifier, region);
151
180
  beaconManager.startMonitoring(region);
@@ -183,6 +212,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
183
212
  String uuid = call.getString("uuid");
184
213
  Integer major = call.getInt("major");
185
214
  Integer minor = call.getInt("minor");
215
+ Boolean enableBackgroundMode = call.getBoolean("enableBackgroundMode");
186
216
 
187
217
  if (identifier == null || uuid == null) {
188
218
  call.reject("Missing required parameters");
@@ -190,6 +220,9 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
190
220
  }
191
221
 
192
222
  try {
223
+ if (enableBackgroundMode != null) {
224
+ setBackgroundModeEnabled(enableBackgroundMode);
225
+ }
193
226
  Region region = createRegion(identifier, uuid, major, minor);
194
227
  rangedRegions.put(identifier, region);
195
228
  beaconManager.startRangingBeacons(region);
@@ -386,26 +419,108 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
386
419
 
387
420
  @PermissionCallback
388
421
  private void bluetoothScanPermissionCallback(PluginCall call) {
389
- // Continue with the original request
390
- requestWhenInUseAuthorization(call);
422
+ // Check if BLUETOOTH_SCAN was granted
423
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
424
+ boolean hasBluetoothScan =
425
+ ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED;
426
+
427
+ if (hasBluetoothScan) {
428
+ // Continue with the original request
429
+ requestWhenInUseAuthorization(call);
430
+ } else {
431
+ // Permission denied, resolve with denied status
432
+ JSObject ret = new JSObject();
433
+ ret.put("status", "denied");
434
+ call.resolve(ret);
435
+ }
436
+ } else {
437
+ // Continue with the original request on older versions
438
+ requestWhenInUseAuthorization(call);
439
+ }
391
440
  }
392
441
 
393
442
  @PermissionCallback
394
443
  private void bluetoothConnectPermissionCallback(PluginCall call) {
395
- // Continue with the original request
396
- requestWhenInUseAuthorization(call);
444
+ // Check if BLUETOOTH_CONNECT was granted
445
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
446
+ boolean hasBluetoothConnect =
447
+ ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_CONNECT) ==
448
+ PackageManager.PERMISSION_GRANTED;
449
+
450
+ if (hasBluetoothConnect) {
451
+ // Continue with the original request
452
+ requestWhenInUseAuthorization(call);
453
+ } else {
454
+ // Permission denied, resolve with denied status
455
+ JSObject ret = new JSObject();
456
+ ret.put("status", "denied");
457
+ call.resolve(ret);
458
+ }
459
+ } else {
460
+ // Continue with the original request on older versions
461
+ requestWhenInUseAuthorization(call);
462
+ }
397
463
  }
398
464
 
399
465
  @PermissionCallback
400
466
  private void bluetoothScanForBackgroundCallback(PluginCall call) {
401
- // Continue with the background authorization flow
402
- requestAlwaysAuthorization(call);
467
+ // Check if BLUETOOTH_SCAN was granted
468
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
469
+ boolean hasBluetoothScan =
470
+ ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED;
471
+
472
+ if (hasBluetoothScan) {
473
+ // Continue with the background authorization flow
474
+ requestAlwaysAuthorization(call);
475
+ } else {
476
+ // Permission denied, check what we can offer
477
+ boolean hasFineLocation =
478
+ ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) ==
479
+ PackageManager.PERMISSION_GRANTED;
480
+
481
+ JSObject ret = new JSObject();
482
+ if (hasFineLocation) {
483
+ ret.put("status", "authorized_when_in_use");
484
+ } else {
485
+ ret.put("status", "denied");
486
+ }
487
+ call.resolve(ret);
488
+ }
489
+ } else {
490
+ // Continue with the background authorization flow on older versions
491
+ requestAlwaysAuthorization(call);
492
+ }
403
493
  }
404
494
 
405
495
  @PermissionCallback
406
496
  private void bluetoothConnectForBackgroundCallback(PluginCall call) {
407
- // Continue with the background authorization flow
408
- requestAlwaysAuthorization(call);
497
+ // Check if BLUETOOTH_CONNECT was granted
498
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
499
+ boolean hasBluetoothConnect =
500
+ ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_CONNECT) ==
501
+ PackageManager.PERMISSION_GRANTED;
502
+
503
+ if (hasBluetoothConnect) {
504
+ // Continue with the background authorization flow
505
+ requestAlwaysAuthorization(call);
506
+ } else {
507
+ // Permission denied, check what we can offer
508
+ boolean hasFineLocation =
509
+ ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) ==
510
+ PackageManager.PERMISSION_GRANTED;
511
+
512
+ JSObject ret = new JSObject();
513
+ if (hasFineLocation) {
514
+ ret.put("status", "authorized_when_in_use");
515
+ } else {
516
+ ret.put("status", "denied");
517
+ }
518
+ call.resolve(ret);
519
+ }
520
+ } else {
521
+ // Continue with the background authorization flow on older versions
522
+ requestAlwaysAuthorization(call);
523
+ }
409
524
  }
410
525
 
411
526
  @PluginMethod
@@ -443,44 +558,7 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
443
558
  public void enableBackgroundMode(PluginCall call) {
444
559
  Boolean enabled = call.getBoolean("enabled", true);
445
560
  try {
446
- if (enabled != null && enabled) {
447
- // Enable foreground service for background beacon scanning
448
- // This is required on Android 8+ for reliable background operation
449
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
450
- // Create notification channel for foreground service
451
- android.app.NotificationChannel channel = new android.app.NotificationChannel(
452
- "beacon_service_channel",
453
- "Beacon Service",
454
- android.app.NotificationManager.IMPORTANCE_LOW
455
- );
456
- channel.setDescription("Background beacon monitoring service");
457
-
458
- android.app.NotificationManager notificationManager = getContext().getSystemService(
459
- android.app.NotificationManager.class
460
- );
461
- if (notificationManager != null) {
462
- notificationManager.createNotificationChannel(channel);
463
- }
464
-
465
- // Build notification for foreground service
466
- android.app.Notification.Builder builder = new android.app.Notification.Builder(getContext(), "beacon_service_channel");
467
- builder.setSmallIcon(android.R.drawable.ic_dialog_info);
468
- builder.setContentTitle("Beacon Monitoring");
469
- builder.setContentText("Scanning for nearby beacons");
470
-
471
- // Enable foreground service mode in AltBeacon
472
- beaconManager.enableForegroundServiceScanning(builder.build(), 456);
473
- }
474
-
475
- // Set background mode
476
- beaconManager.setBackgroundMode(true);
477
- } else {
478
- // Disable background mode
479
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
480
- beaconManager.disableForegroundServiceScanning();
481
- }
482
- beaconManager.setBackgroundMode(false);
483
- }
561
+ setBackgroundModeEnabled(enabled != null && enabled);
484
562
  call.resolve();
485
563
  } catch (Exception e) {
486
564
  call.reject("Failed to enable background mode", e);
@@ -608,4 +686,63 @@ public class CapacitorIbeaconPlugin extends Plugin implements BeaconConsumer {
608
686
  return "far";
609
687
  }
610
688
  }
689
+
690
+ private void setBackgroundModeEnabled(boolean enabled) {
691
+ backgroundModeEnabled = enabled;
692
+ applyBackgroundMode(enabled);
693
+ }
694
+
695
+ private void applyBackgroundMode(boolean enabled) {
696
+ if (beaconManager == null) {
697
+ return;
698
+ }
699
+
700
+ boolean shouldEnableBackgroundMode = enabled && isInBackground;
701
+
702
+ if (shouldEnableBackgroundMode) {
703
+ enableForegroundServiceIfNeeded();
704
+ beaconManager.setBackgroundMode(true);
705
+ } else {
706
+ disableForegroundServiceIfNeeded();
707
+ beaconManager.setBackgroundMode(false);
708
+ }
709
+ }
710
+
711
+ private void enableForegroundServiceIfNeeded() {
712
+ if (foregroundServiceEnabled || Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
713
+ return;
714
+ }
715
+
716
+ // Create notification channel for foreground service
717
+ android.app.NotificationChannel channel = new android.app.NotificationChannel(
718
+ FOREGROUND_CHANNEL_ID,
719
+ "Beacon Service",
720
+ android.app.NotificationManager.IMPORTANCE_LOW
721
+ );
722
+ channel.setDescription("Background beacon monitoring service");
723
+
724
+ android.app.NotificationManager notificationManager = getContext().getSystemService(android.app.NotificationManager.class);
725
+ if (notificationManager != null) {
726
+ notificationManager.createNotificationChannel(channel);
727
+ }
728
+
729
+ // Build notification for foreground service
730
+ android.app.Notification.Builder builder = new android.app.Notification.Builder(getContext(), FOREGROUND_CHANNEL_ID);
731
+ builder.setSmallIcon(android.R.drawable.ic_dialog_info);
732
+ builder.setContentTitle("Beacon Monitoring");
733
+ builder.setContentText("Scanning for nearby beacons");
734
+
735
+ // Enable foreground service mode in AltBeacon
736
+ beaconManager.enableForegroundServiceScanning(builder.build(), FOREGROUND_NOTIFICATION_ID);
737
+ foregroundServiceEnabled = true;
738
+ }
739
+
740
+ private void disableForegroundServiceIfNeeded() {
741
+ if (!foregroundServiceEnabled || Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
742
+ return;
743
+ }
744
+
745
+ beaconManager.disableForegroundServiceScanning();
746
+ foregroundServiceEnabled = false;
747
+ }
611
748
  }
package/dist/docs.json CHANGED
@@ -526,6 +526,254 @@
526
526
  "BackgroundScanPeriodOptions"
527
527
  ],
528
528
  "slug": "setbackgroundscanperiod"
529
+ },
530
+ {
531
+ "name": "addListener",
532
+ "signature": "(eventName: 'didRangeBeacons', listenerFunc: (data: RangingEventData) => void) => Promise<PluginListenerHandle>",
533
+ "parameters": [
534
+ {
535
+ "name": "eventName",
536
+ "docs": "- The event name ('didRangeBeacons')",
537
+ "type": "'didRangeBeacons'"
538
+ },
539
+ {
540
+ "name": "listenerFunc",
541
+ "docs": "- Callback function that receives beacon data",
542
+ "type": "(data: RangingEventData) => void"
543
+ }
544
+ ],
545
+ "returns": "Promise<PluginListenerHandle>",
546
+ "tags": [
547
+ {
548
+ "name": "param",
549
+ "text": "eventName - The event name ('didRangeBeacons')"
550
+ },
551
+ {
552
+ "name": "param",
553
+ "text": "listenerFunc - Callback function that receives beacon data"
554
+ },
555
+ {
556
+ "name": "returns",
557
+ "text": "Promise that resolves with a PluginListenerHandle"
558
+ },
559
+ {
560
+ "name": "since",
561
+ "text": "1.0.0"
562
+ },
563
+ {
564
+ "name": "example",
565
+ "text": "```typescript\nconst listener = await CapacitorIbeacon.addListener('didRangeBeacons', (data) => {\n console.log('Beacons:', data.beacons);\n});\n// Remove listener when done\nawait listener.remove();\n```"
566
+ }
567
+ ],
568
+ "docs": "Listen for beacon ranging events.",
569
+ "complexTypes": [
570
+ "PluginListenerHandle",
571
+ "RangingEventData"
572
+ ],
573
+ "slug": "addlistenerdidrangebeacons-"
574
+ },
575
+ {
576
+ "name": "addListener",
577
+ "signature": "(eventName: 'didEnterRegion', listenerFunc: (data: { region: BeaconRegion; }) => void) => Promise<PluginListenerHandle>",
578
+ "parameters": [
579
+ {
580
+ "name": "eventName",
581
+ "docs": "- The event name ('didEnterRegion')",
582
+ "type": "'didEnterRegion'"
583
+ },
584
+ {
585
+ "name": "listenerFunc",
586
+ "docs": "- Callback function that receives region data",
587
+ "type": "(data: { region: BeaconRegion; }) => void"
588
+ }
589
+ ],
590
+ "returns": "Promise<PluginListenerHandle>",
591
+ "tags": [
592
+ {
593
+ "name": "param",
594
+ "text": "eventName - The event name ('didEnterRegion')"
595
+ },
596
+ {
597
+ "name": "param",
598
+ "text": "listenerFunc - Callback function that receives region data"
599
+ },
600
+ {
601
+ "name": "returns",
602
+ "text": "Promise that resolves with a PluginListenerHandle"
603
+ },
604
+ {
605
+ "name": "since",
606
+ "text": "1.0.0"
607
+ },
608
+ {
609
+ "name": "example",
610
+ "text": "```typescript\nconst listener = await CapacitorIbeacon.addListener('didEnterRegion', (data) => {\n console.log('Entered region:', data.region.identifier);\n});\n```"
611
+ }
612
+ ],
613
+ "docs": "Listen for region enter events.",
614
+ "complexTypes": [
615
+ "PluginListenerHandle",
616
+ "BeaconRegion"
617
+ ],
618
+ "slug": "addlistenerdidenterregion-"
619
+ },
620
+ {
621
+ "name": "addListener",
622
+ "signature": "(eventName: 'didExitRegion', listenerFunc: (data: { region: BeaconRegion; }) => void) => Promise<PluginListenerHandle>",
623
+ "parameters": [
624
+ {
625
+ "name": "eventName",
626
+ "docs": "- The event name ('didExitRegion')",
627
+ "type": "'didExitRegion'"
628
+ },
629
+ {
630
+ "name": "listenerFunc",
631
+ "docs": "- Callback function that receives region data",
632
+ "type": "(data: { region: BeaconRegion; }) => void"
633
+ }
634
+ ],
635
+ "returns": "Promise<PluginListenerHandle>",
636
+ "tags": [
637
+ {
638
+ "name": "param",
639
+ "text": "eventName - The event name ('didExitRegion')"
640
+ },
641
+ {
642
+ "name": "param",
643
+ "text": "listenerFunc - Callback function that receives region data"
644
+ },
645
+ {
646
+ "name": "returns",
647
+ "text": "Promise that resolves with a PluginListenerHandle"
648
+ },
649
+ {
650
+ "name": "since",
651
+ "text": "1.0.0"
652
+ },
653
+ {
654
+ "name": "example",
655
+ "text": "```typescript\nconst listener = await CapacitorIbeacon.addListener('didExitRegion', (data) => {\n console.log('Exited region:', data.region.identifier);\n});\n```"
656
+ }
657
+ ],
658
+ "docs": "Listen for region exit events.",
659
+ "complexTypes": [
660
+ "PluginListenerHandle",
661
+ "BeaconRegion"
662
+ ],
663
+ "slug": "addlistenerdidexitregion-"
664
+ },
665
+ {
666
+ "name": "addListener",
667
+ "signature": "(eventName: 'didDetermineStateForRegion', listenerFunc: (data: MonitoringEventData) => void) => Promise<PluginListenerHandle>",
668
+ "parameters": [
669
+ {
670
+ "name": "eventName",
671
+ "docs": "- The event name ('didDetermineStateForRegion')",
672
+ "type": "'didDetermineStateForRegion'"
673
+ },
674
+ {
675
+ "name": "listenerFunc",
676
+ "docs": "- Callback function that receives region and state data",
677
+ "type": "(data: MonitoringEventData) => void"
678
+ }
679
+ ],
680
+ "returns": "Promise<PluginListenerHandle>",
681
+ "tags": [
682
+ {
683
+ "name": "param",
684
+ "text": "eventName - The event name ('didDetermineStateForRegion')"
685
+ },
686
+ {
687
+ "name": "param",
688
+ "text": "listenerFunc - Callback function that receives region and state data"
689
+ },
690
+ {
691
+ "name": "returns",
692
+ "text": "Promise that resolves with a PluginListenerHandle"
693
+ },
694
+ {
695
+ "name": "since",
696
+ "text": "1.0.0"
697
+ },
698
+ {
699
+ "name": "example",
700
+ "text": "```typescript\nconst listener = await CapacitorIbeacon.addListener('didDetermineStateForRegion', (data) => {\n console.log('Region state:', data.state, 'for', data.region.identifier);\n});\n```"
701
+ }
702
+ ],
703
+ "docs": "Listen for region state determination events.",
704
+ "complexTypes": [
705
+ "PluginListenerHandle",
706
+ "MonitoringEventData"
707
+ ],
708
+ "slug": "addlistenerdiddeterminestateforregion-"
709
+ },
710
+ {
711
+ "name": "addListener",
712
+ "signature": "(eventName: 'monitoringDidFailForRegion', listenerFunc: (data: { region: BeaconRegion; error: string; }) => void) => Promise<PluginListenerHandle>",
713
+ "parameters": [
714
+ {
715
+ "name": "eventName",
716
+ "docs": "- The event name ('monitoringDidFailForRegion')",
717
+ "type": "'monitoringDidFailForRegion'"
718
+ },
719
+ {
720
+ "name": "listenerFunc",
721
+ "docs": "- Callback function that receives error data",
722
+ "type": "(data: { region: BeaconRegion; error: string; }) => void"
723
+ }
724
+ ],
725
+ "returns": "Promise<PluginListenerHandle>",
726
+ "tags": [
727
+ {
728
+ "name": "param",
729
+ "text": "eventName - The event name ('monitoringDidFailForRegion')"
730
+ },
731
+ {
732
+ "name": "param",
733
+ "text": "listenerFunc - Callback function that receives error data"
734
+ },
735
+ {
736
+ "name": "returns",
737
+ "text": "Promise that resolves with a PluginListenerHandle"
738
+ },
739
+ {
740
+ "name": "since",
741
+ "text": "1.0.0"
742
+ },
743
+ {
744
+ "name": "example",
745
+ "text": "```typescript\nconst listener = await CapacitorIbeacon.addListener('monitoringDidFailForRegion', (data) => {\n console.error('Monitoring failed:', data.error);\n});\n```"
746
+ }
747
+ ],
748
+ "docs": "Listen for monitoring failure events.",
749
+ "complexTypes": [
750
+ "PluginListenerHandle",
751
+ "BeaconRegion"
752
+ ],
753
+ "slug": "addlistenermonitoringdidfailforregion-"
754
+ },
755
+ {
756
+ "name": "removeAllListeners",
757
+ "signature": "() => Promise<void>",
758
+ "parameters": [],
759
+ "returns": "Promise<void>",
760
+ "tags": [
761
+ {
762
+ "name": "returns",
763
+ "text": "Promise that resolves when all listeners are removed"
764
+ },
765
+ {
766
+ "name": "since",
767
+ "text": "1.0.0"
768
+ },
769
+ {
770
+ "name": "example",
771
+ "text": "```typescript\nawait CapacitorIbeacon.removeAllListeners();\n```"
772
+ }
773
+ ],
774
+ "docs": "Remove all listeners for this plugin.",
775
+ "complexTypes": [],
776
+ "slug": "removealllisteners"
529
777
  }
530
778
  ],
531
779
  "properties": []
@@ -572,6 +820,13 @@
572
820
  "docs": "Notify when device enters region (iOS only).",
573
821
  "complexTypes": [],
574
822
  "type": "boolean | undefined"
823
+ },
824
+ {
825
+ "name": "enableBackgroundMode",
826
+ "tags": [],
827
+ "docs": "Enable Android background mode for this monitoring/ranging call.\nWhen true, the plugin will keep scanning in background using a foreground service.",
828
+ "complexTypes": [],
829
+ "type": "boolean | undefined"
575
830
  }
576
831
  ]
577
832
  },
@@ -641,6 +896,125 @@
641
896
  "type": "number | undefined"
642
897
  }
643
898
  ]
899
+ },
900
+ {
901
+ "name": "PluginListenerHandle",
902
+ "slug": "pluginlistenerhandle",
903
+ "docs": "",
904
+ "tags": [],
905
+ "methods": [],
906
+ "properties": [
907
+ {
908
+ "name": "remove",
909
+ "tags": [],
910
+ "docs": "",
911
+ "complexTypes": [],
912
+ "type": "() => Promise<void>"
913
+ }
914
+ ]
915
+ },
916
+ {
917
+ "name": "RangingEventData",
918
+ "slug": "rangingeventdata",
919
+ "docs": "Event data when beacons are ranged.",
920
+ "tags": [],
921
+ "methods": [],
922
+ "properties": [
923
+ {
924
+ "name": "region",
925
+ "tags": [],
926
+ "docs": "Region that was ranged.",
927
+ "complexTypes": [
928
+ "BeaconRegion"
929
+ ],
930
+ "type": "BeaconRegion"
931
+ },
932
+ {
933
+ "name": "beacons",
934
+ "tags": [],
935
+ "docs": "Array of detected beacons.",
936
+ "complexTypes": [
937
+ "Beacon"
938
+ ],
939
+ "type": "Beacon[]"
940
+ }
941
+ ]
942
+ },
943
+ {
944
+ "name": "Beacon",
945
+ "slug": "beacon",
946
+ "docs": "Detected beacon information.",
947
+ "tags": [],
948
+ "methods": [],
949
+ "properties": [
950
+ {
951
+ "name": "uuid",
952
+ "tags": [],
953
+ "docs": "Beacon UUID.",
954
+ "complexTypes": [],
955
+ "type": "string"
956
+ },
957
+ {
958
+ "name": "major",
959
+ "tags": [],
960
+ "docs": "Major value.",
961
+ "complexTypes": [],
962
+ "type": "number"
963
+ },
964
+ {
965
+ "name": "minor",
966
+ "tags": [],
967
+ "docs": "Minor value.",
968
+ "complexTypes": [],
969
+ "type": "number"
970
+ },
971
+ {
972
+ "name": "rssi",
973
+ "tags": [],
974
+ "docs": "RSSI (Received Signal Strength Indicator).",
975
+ "complexTypes": [],
976
+ "type": "number"
977
+ },
978
+ {
979
+ "name": "proximity",
980
+ "tags": [],
981
+ "docs": "Proximity: 'immediate', 'near', 'far', or 'unknown'.",
982
+ "complexTypes": [],
983
+ "type": "'immediate' | 'near' | 'far' | 'unknown'"
984
+ },
985
+ {
986
+ "name": "accuracy",
987
+ "tags": [],
988
+ "docs": "Estimated distance in meters.",
989
+ "complexTypes": [],
990
+ "type": "number"
991
+ }
992
+ ]
993
+ },
994
+ {
995
+ "name": "MonitoringEventData",
996
+ "slug": "monitoringeventdata",
997
+ "docs": "Event data when entering or exiting a region.",
998
+ "tags": [],
999
+ "methods": [],
1000
+ "properties": [
1001
+ {
1002
+ "name": "region",
1003
+ "tags": [],
1004
+ "docs": "Region that triggered the event.",
1005
+ "complexTypes": [
1006
+ "BeaconRegion"
1007
+ ],
1008
+ "type": "BeaconRegion"
1009
+ },
1010
+ {
1011
+ "name": "state",
1012
+ "tags": [],
1013
+ "docs": "Event state: 'enter' or 'exit'.",
1014
+ "complexTypes": [],
1015
+ "type": "'enter' | 'exit'"
1016
+ }
1017
+ ]
644
1018
  }
645
1019
  ],
646
1020
  "enums": [],
@@ -1,9 +1,10 @@
1
+ import type { Plugin, PluginListenerHandle } from '@capacitor/core';
1
2
  /**
2
3
  * Capacitor iBeacon Plugin - Proximity detection and beacon region monitoring.
3
4
  *
4
5
  * @since 1.0.0
5
6
  */
6
- export interface CapacitorIbeaconPlugin {
7
+ export interface CapacitorIbeaconPlugin extends Plugin {
7
8
  /**
8
9
  * Start monitoring for a beacon region. Triggers events when entering/exiting the region.
9
10
  *
@@ -253,6 +254,101 @@ export interface CapacitorIbeaconPlugin {
253
254
  * ```
254
255
  */
255
256
  setBackgroundScanPeriod(options: BackgroundScanPeriodOptions): Promise<void>;
257
+ /**
258
+ * Listen for beacon ranging events.
259
+ *
260
+ * @param eventName - The event name ('didRangeBeacons')
261
+ * @param listenerFunc - Callback function that receives beacon data
262
+ * @returns Promise that resolves with a PluginListenerHandle
263
+ * @since 1.0.0
264
+ * @example
265
+ * ```typescript
266
+ * const listener = await CapacitorIbeacon.addListener('didRangeBeacons', (data) => {
267
+ * console.log('Beacons:', data.beacons);
268
+ * });
269
+ * // Remove listener when done
270
+ * await listener.remove();
271
+ * ```
272
+ */
273
+ addListener(eventName: 'didRangeBeacons', listenerFunc: (data: RangingEventData) => void): Promise<PluginListenerHandle>;
274
+ /**
275
+ * Listen for region enter events.
276
+ *
277
+ * @param eventName - The event name ('didEnterRegion')
278
+ * @param listenerFunc - Callback function that receives region data
279
+ * @returns Promise that resolves with a PluginListenerHandle
280
+ * @since 1.0.0
281
+ * @example
282
+ * ```typescript
283
+ * const listener = await CapacitorIbeacon.addListener('didEnterRegion', (data) => {
284
+ * console.log('Entered region:', data.region.identifier);
285
+ * });
286
+ * ```
287
+ */
288
+ addListener(eventName: 'didEnterRegion', listenerFunc: (data: {
289
+ region: BeaconRegion;
290
+ }) => void): Promise<PluginListenerHandle>;
291
+ /**
292
+ * Listen for region exit events.
293
+ *
294
+ * @param eventName - The event name ('didExitRegion')
295
+ * @param listenerFunc - Callback function that receives region data
296
+ * @returns Promise that resolves with a PluginListenerHandle
297
+ * @since 1.0.0
298
+ * @example
299
+ * ```typescript
300
+ * const listener = await CapacitorIbeacon.addListener('didExitRegion', (data) => {
301
+ * console.log('Exited region:', data.region.identifier);
302
+ * });
303
+ * ```
304
+ */
305
+ addListener(eventName: 'didExitRegion', listenerFunc: (data: {
306
+ region: BeaconRegion;
307
+ }) => void): Promise<PluginListenerHandle>;
308
+ /**
309
+ * Listen for region state determination events.
310
+ *
311
+ * @param eventName - The event name ('didDetermineStateForRegion')
312
+ * @param listenerFunc - Callback function that receives region and state data
313
+ * @returns Promise that resolves with a PluginListenerHandle
314
+ * @since 1.0.0
315
+ * @example
316
+ * ```typescript
317
+ * const listener = await CapacitorIbeacon.addListener('didDetermineStateForRegion', (data) => {
318
+ * console.log('Region state:', data.state, 'for', data.region.identifier);
319
+ * });
320
+ * ```
321
+ */
322
+ addListener(eventName: 'didDetermineStateForRegion', listenerFunc: (data: MonitoringEventData) => void): Promise<PluginListenerHandle>;
323
+ /**
324
+ * Listen for monitoring failure events.
325
+ *
326
+ * @param eventName - The event name ('monitoringDidFailForRegion')
327
+ * @param listenerFunc - Callback function that receives error data
328
+ * @returns Promise that resolves with a PluginListenerHandle
329
+ * @since 1.0.0
330
+ * @example
331
+ * ```typescript
332
+ * const listener = await CapacitorIbeacon.addListener('monitoringDidFailForRegion', (data) => {
333
+ * console.error('Monitoring failed:', data.error);
334
+ * });
335
+ * ```
336
+ */
337
+ addListener(eventName: 'monitoringDidFailForRegion', listenerFunc: (data: {
338
+ region: BeaconRegion;
339
+ error: string;
340
+ }) => void): Promise<PluginListenerHandle>;
341
+ /**
342
+ * Remove all listeners for this plugin.
343
+ *
344
+ * @returns Promise that resolves when all listeners are removed
345
+ * @since 1.0.0
346
+ * @example
347
+ * ```typescript
348
+ * await CapacitorIbeacon.removeAllListeners();
349
+ * ```
350
+ */
351
+ removeAllListeners(): Promise<void>;
256
352
  }
257
353
  /**
258
354
  * Beacon region definition for monitoring and ranging.
@@ -278,6 +374,11 @@ export interface BeaconRegion {
278
374
  * Notify when device enters region (iOS only).
279
375
  */
280
376
  notifyEntryStateOnDisplay?: boolean;
377
+ /**
378
+ * Enable Android background mode for this monitoring/ranging call.
379
+ * When true, the plugin will keep scanning in background using a foreground service.
380
+ */
381
+ enableBackgroundMode?: boolean;
281
382
  }
282
383
  /**
283
384
  * Background scan period configuration options (Android only).
@@ -374,35 +475,3 @@ export interface MonitoringEventData {
374
475
  */
375
476
  state: 'enter' | 'exit';
376
477
  }
377
- /**
378
- * Event listeners for iBeacon plugin.
379
- */
380
- export interface BeaconEventListeners {
381
- /**
382
- * Called when beacons are detected during ranging.
383
- */
384
- didRangeBeacons?: (data: RangingEventData) => void;
385
- /**
386
- * Called when entering or exiting a monitored region.
387
- */
388
- didDetermineStateForRegion?: (data: MonitoringEventData) => void;
389
- /**
390
- * Called when entering a monitored region.
391
- */
392
- didEnterRegion?: (data: {
393
- region: BeaconRegion;
394
- }) => void;
395
- /**
396
- * Called when exiting a monitored region.
397
- */
398
- didExitRegion?: (data: {
399
- region: BeaconRegion;
400
- }) => void;
401
- /**
402
- * Called when monitoring state changes.
403
- */
404
- monitoringDidFailForRegion?: (data: {
405
- region: BeaconRegion;
406
- error: string;
407
- }) => void;
408
- }
@@ -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.1"
7
+ private let pluginVersion: String = "8.1.3"
8
8
  public let identifier = "CapacitorIbeaconPlugin"
9
9
  public let jsName = "CapacitorIbeacon"
10
10
  public let pluginMethods: [CAPPluginMethod] = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-ibeacon",
3
- "version": "8.1.1",
3
+ "version": "8.1.3",
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",