# Cordova iBeacon Plugin This is a Cordova/Phonegap plugin that enables proximity beacon monitoring and transmission for iOS and Android platforms. The plugin provides a JavaScript API for detecting and ranging iBeacons (Bluetooth Low Energy beacons), monitoring geographic regions, and advertising the device itself as an iBeacon. It closely mirrors Apple's CLLocationManager API, making it familiar to iOS developers while providing cross-platform support. The plugin bridges native iOS CoreLocation and Android AltBeacon functionality to JavaScript, using promises for asynchronous operations. It supports both monitoring (detecting when entering/exiting beacon regions) and ranging (measuring distance to nearby beacons). On iOS, it also enables devices to advertise themselves as beacons, useful for peer-to-peer proximity applications. The API is accessed through `cordova.plugins.locationManager` and uses a delegate pattern for handling asynchronous events from the native layer. ## API Documentation ### Creating a Beacon Region Create a BeaconRegion object to define which beacons to monitor or range. ```javascript // Basic beacon region with UUID, major, and minor var uuid = '00000000-0000-0000-0000-000000000000'; var identifier = 'myBeaconRegion'; var major = 5; var minor = 1000; var beaconRegion = new cordova.plugins.locationManager.BeaconRegion( identifier, uuid, major, minor ); // Beacon region with only UUID (major and minor as wildcards) var wildcardBeacon = new cordova.plugins.locationManager.BeaconRegion( 'anyBeacon', '00000000-0000-0000-0000-000000000000' ); // Android wildcard UUID (matches any beacon) var androidWildcard = new cordova.plugins.locationManager.BeaconRegion( 'allBeacons', cordova.plugins.locationManager.BeaconRegion.WILDCARD_UUID ); ``` ### Setting Up a Delegate Configure event handlers for beacon and region events. ```javascript var delegate = new cordova.plugins.locationManager.Delegate(); // Called when determining the state of a region delegate.didDetermineStateForRegion = function(pluginResult) { console.log('Region state:', pluginResult.state); console.log('Region:', JSON.stringify(pluginResult.region)); }; // Called when monitoring starts for a region delegate.didStartMonitoringForRegion = function(pluginResult) { console.log('Started monitoring:', JSON.stringify(pluginResult.region)); }; // Called when entering a region delegate.didEnterRegion = function(pluginResult) { console.log('Entered region:', JSON.stringify(pluginResult.region)); }; // Called when exiting a region delegate.didExitRegion = function(pluginResult) { console.log('Exited region:', JSON.stringify(pluginResult.region)); }; // Called continuously while ranging (contains distance info) delegate.didRangeBeaconsInRegion = function(pluginResult) { console.log('Ranged beacons:', pluginResult.beacons.length); pluginResult.beacons.forEach(function(beacon) { console.log('Beacon:', beacon.uuid, 'Distance:', beacon.accuracy + 'm'); }); }; // Set the delegate cordova.plugins.locationManager.setDelegate(delegate); ``` ### Monitoring for Beacons Start and stop monitoring for beacon regions (background capable). ```javascript var uuid = 'B9407F30-F5F8-466E-AFF9-25556B57FE6D'; var identifier = 'estimoteBeacon'; var beaconRegion = new cordova.plugins.locationManager.BeaconRegion( identifier, uuid ); var delegate = new cordova.plugins.locationManager.Delegate(); delegate.didDetermineStateForRegion = function(pluginResult) { var state = pluginResult.state === 'CLRegionStateInside' ? 'inside' : 'outside'; console.log('User is ' + state + ' the region'); }; delegate.didEnterRegion = function(pluginResult) { console.log('Entered beacon region!'); // Trigger notification, start ranging, etc. }; delegate.didExitRegion = function(pluginResult) { console.log('Left beacon region'); }; cordova.plugins.locationManager.setDelegate(delegate); // Request iOS permissions (iOS 8+) cordova.plugins.locationManager.requestAlwaysAuthorization(); // Start monitoring cordova.plugins.locationManager.startMonitoringForRegion(beaconRegion) .then(function() { console.log('Monitoring started successfully'); }) .fail(function(error) { console.error('Failed to start monitoring:', error); }) .done(); // Stop monitoring when done cordova.plugins.locationManager.stopMonitoringForRegion(beaconRegion) .fail(function(error) { console.error('Failed to stop monitoring:', error); }) .done(); ``` ### Ranging Beacons Measure distance to nearby beacons in real-time. ```javascript var uuid = 'B9407F30-F5F8-466E-AFF9-25556B57FE6D'; var identifier = 'myBeacons'; var beaconRegion = new cordova.plugins.locationManager.BeaconRegion( identifier, uuid ); var delegate = new cordova.plugins.locationManager.Delegate(); delegate.didRangeBeaconsInRegion = function(pluginResult) { console.log('Found ' + pluginResult.beacons.length + ' beacons'); pluginResult.beacons.forEach(function(beacon) { console.log('UUID:', beacon.uuid); console.log('Major:', beacon.major); console.log('Minor:', beacon.minor); console.log('Proximity:', beacon.proximity); // immediate, near, far, unknown console.log('Accuracy:', beacon.accuracy + ' meters'); console.log('RSSI:', beacon.rssi + ' dBm'); }); }; cordova.plugins.locationManager.setDelegate(delegate); cordova.plugins.locationManager.requestWhenInUseAuthorization(); // Start ranging cordova.plugins.locationManager.startRangingBeaconsInRegion(beaconRegion) .then(function() { console.log('Ranging started'); }) .fail(function(error) { console.error('Ranging failed:', error); }) .done(); // Stop ranging cordova.plugins.locationManager.stopRangingBeaconsInRegion(beaconRegion) .fail(function(error) { console.error('Failed to stop ranging:', error); }) .done(); ``` ### Advertising as a Beacon (iOS only) Make the device transmit as an iBeacon. ```javascript var uuid = 'DA5336AE-2042-453A-A57F-F80DD34DFCD9'; var identifier = 'advertisedBeacon'; var major = 1; var minor = 100; var beaconRegion = new cordova.plugins.locationManager.BeaconRegion( identifier, uuid, major, minor ); var delegate = new cordova.plugins.locationManager.Delegate(); // Called when advertising starts delegate.peripheralManagerDidStartAdvertising = function(pluginResult) { if (pluginResult.error) { console.error('Advertising error:', pluginResult.error); } else { console.log('Now advertising as:', JSON.stringify(pluginResult.region)); } }; // Called when bluetooth state changes delegate.peripheralManagerDidUpdateState = function(pluginResult) { console.log('Bluetooth state:', pluginResult.state); // BluetoothManagerStatePoweredOn = ready // BluetoothManagerStatePoweredOff = bluetooth off }; cordova.plugins.locationManager.setDelegate(delegate); // Check if advertising is supported cordova.plugins.locationManager.isAdvertisingAvailable() .then(function(isSupported) { if (isSupported) { console.log('Advertising is supported'); // Optional: specify measured power (defaults to device calibration) var measuredPower = -59; // RSSI at 1 meter return cordova.plugins.locationManager.startAdvertising( beaconRegion, measuredPower ); } else { throw new Error('Advertising not supported on this device'); } }) .then(function() { console.log('Advertising request sent'); }) .fail(function(error) { console.error('Advertising failed:', error); }) .done(); // Stop advertising cordova.plugins.locationManager.stopAdvertising() .then(function() { console.log('Stopped advertising'); }) .fail(function(error) { console.error('Failed to stop advertising:', error); }) .done(); ``` ### Bluetooth Management (Android only) Enable or disable Bluetooth programmatically on Android. ```javascript // Check if Bluetooth is enabled cordova.plugins.locationManager.isBluetoothEnabled() .then(function(isEnabled) { console.log('Bluetooth enabled:', isEnabled); if (isEnabled) { // Disable Bluetooth return cordova.plugins.locationManager.disableBluetooth(); } else { // Enable Bluetooth return cordova.plugins.locationManager.enableBluetooth(); } }) .then(function() { console.log('Bluetooth state changed successfully'); }) .fail(function(error) { console.error('Bluetooth operation failed:', error); }) .done(); ``` ### Requesting Permissions (iOS 8+) Request location permissions required for beacon monitoring. ```javascript // Request "When In Use" permission (foreground only) cordova.plugins.locationManager.requestWhenInUseAuthorization() .then(function() { console.log('Permission requested'); }) .fail(function(error) { console.error('Permission request failed:', error); }) .done(); // Request "Always" permission (background monitoring) cordova.plugins.locationManager.requestAlwaysAuthorization() .then(function() { console.log('Always permission requested'); }) .fail(function(error) { console.error('Permission request failed:', error); }) .done(); // Check current authorization status cordova.plugins.locationManager.getAuthorizationStatus() .then(function(status) { console.log('Authorization status:', status); // CLAuthorizationStatusNotDetermined // CLAuthorizationStatusRestricted // CLAuthorizationStatusDenied // CLAuthorizationStatusAuthorizedWhenInUse // CLAuthorizationStatusAuthorizedAlways }) .fail(function(error) { console.error('Failed to get status:', error); }) .done(); ``` ### Creating Circular Regions (iOS only) Monitor geographic regions using latitude, longitude, and radius. ```javascript var identifier = 'myOffice'; var latitude = 37.7749; var longitude = -122.4194; var radius = 100; // meters var circularRegion = new cordova.plugins.locationManager.CircularRegion( identifier, latitude, longitude, radius ); var delegate = new cordova.plugins.locationManager.Delegate(); delegate.didEnterRegion = function(pluginResult) { console.log('Entered location:', pluginResult.region.identifier); }; delegate.didExitRegion = function(pluginResult) { console.log('Left location:', pluginResult.region.identifier); }; cordova.plugins.locationManager.setDelegate(delegate); cordova.plugins.locationManager.requestAlwaysAuthorization(); // Start monitoring the geographic region cordova.plugins.locationManager.startMonitoringForRegion(circularRegion) .then(function() { console.log('Started monitoring geographic region'); }) .fail(function(error) { console.error('Failed:', error); }) .done(); ``` ### Querying Monitored and Ranged Regions Retrieve currently active regions. ```javascript // Get all monitored regions cordova.plugins.locationManager.getMonitoredRegions() .then(function(regions) { console.log('Monitoring ' + regions.length + ' regions'); regions.forEach(function(region) { console.log('Region:', region.identifier, region.typeName); }); }) .fail(function(error) { console.error('Failed to get monitored regions:', error); }) .done(); // Get all ranged regions cordova.plugins.locationManager.getRangedRegions() .then(function(regions) { console.log('Ranging ' + regions.length + ' regions'); regions.forEach(function(region) { console.log('Region:', region.identifier); }); }) .fail(function(error) { console.error('Failed to get ranged regions:', error); }) .done(); ``` ### Checking Feature Availability Verify device capabilities before using features. ```javascript // Check if ranging is available cordova.plugins.locationManager.isRangingAvailable() .then(function(isAvailable) { console.log('Ranging available:', isAvailable); }) .fail(function(error) { console.error('Failed to check ranging:', error); }) .done(); // Check if advertising is available (iOS only) cordova.plugins.locationManager.isAdvertisingAvailable() .then(function(isAvailable) { console.log('Advertising available:', isAvailable); }) .fail(function(error) { console.error('Failed to check advertising:', error); }) .done(); // Check if advertising is currently active cordova.plugins.locationManager.isAdvertising() .then(function(isActive) { console.log('Currently advertising:', isActive); }) .fail(function(error) { console.error('Failed to check advertising status:', error); }) .done(); // Check if monitoring is available for a specific region type var beaconRegion = new cordova.plugins.locationManager.BeaconRegion( 'test', '00000000-0000-0000-0000-000000000000' ); cordova.plugins.locationManager.isMonitoringAvailableForClass(beaconRegion) .then(function(isAvailable) { console.log('Monitoring available for BeaconRegion:', isAvailable); }) .fail(function(error) { console.error('Failed to check monitoring:', error); }) .done(); ``` ### Debug Logging Enable or disable native layer logging for debugging. ```javascript // Enable debug logs in native code cordova.plugins.locationManager.enableDebugLogs() .then(function() { console.log('Debug logging enabled'); }) .done(); // Disable debug logs cordova.plugins.locationManager.disableDebugLogs() .then(function() { console.log('Debug logging disabled'); }) .done(); // Enable debug notifications (iOS only - shows local notifications) cordova.plugins.locationManager.enableDebugNotifications() .then(function() { console.log('Debug notifications enabled'); }) .done(); // Disable debug notifications cordova.plugins.locationManager.disableDebugNotifications() .then(function() { console.log('Debug notifications disabled'); }) .done(); // Append custom message to device log cordova.plugins.locationManager.appendToDeviceLog('Custom debug message') .then(function(message) { console.log('Logged:', message); }) .done(); ``` ## Summary This plugin is ideal for proximity-based mobile applications including retail (beacon-triggered offers), museums (location-based content), events (attendee tracking), smart buildings (room occupancy), asset tracking, and contactless check-ins. The monitoring feature enables background detection of beacon regions even when the app is not running, making it suitable for triggering notifications or actions based on user location. The ranging feature provides real-time distance measurements for interactive experiences that respond to user proximity. Integration is straightforward through the `cordova.plugins.locationManager` API, which uses promises for all asynchronous operations and a delegate pattern for event handling. The plugin handles the complexity of native platform differences, providing a unified JavaScript API for both iOS CoreLocation and Android AltBeacon libraries. Configuration is done via `config.xml` preferences for Android-specific features like ARMA filtering and permission requests. The plugin requires appropriate permissions (location for iOS, location and Bluetooth for Android) and Bluetooth hardware support on the device.