From 0f85ce268a2a265dad4a5cc645ea2c16cabe1d8f Mon Sep 17 00:00:00 2001 From: matti-ida Date: Mon, 13 May 2024 10:46:52 +0300 Subject: [PATCH 1/2] Radio scan callbacks (#70) NOTE! To enable the callbacks, please contact IndoorAtlas support. --- .gitignore | 1 + plugin.xml | 6 + .../ialocation/plugin/IALocationPlugin.java | 82 ++++++++++ .../plugin/IndoorLocationListener.java | 120 ++++++++++++++- src/ios/IndoorAtlasLocationService.h | 8 + src/ios/IndoorAtlasLocationService.m | 27 ++++ src/ios/IndoorLocation.h | 2 + src/ios/IndoorLocation.m | 78 ++++++++++ www/IndoorAtlas.js | 145 ++++++++++++++++++ www/RadioScan.js | 62 ++++++++ 10 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 www/RadioScan.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..08a55c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.gradle diff --git a/plugin.xml b/plugin.xml index 1181db0..ad3aa13 100644 --- a/plugin.xml +++ b/plugin.xml @@ -48,6 +48,9 @@ + + + @@ -57,6 +60,9 @@ Platform location requested for better indoor positioning experience. + + Device motion requested for better indoor positioning experience. + diff --git a/src/android/src/main/java/com/ialocation/plugin/IALocationPlugin.java b/src/android/src/main/java/com/ialocation/plugin/IALocationPlugin.java index c09eca6..79680d4 100644 --- a/src/android/src/main/java/com/ialocation/plugin/IALocationPlugin.java +++ b/src/android/src/main/java/com/ialocation/plugin/IALocationPlugin.java @@ -21,6 +21,7 @@ import com.indooratlas.android.sdk.IARoute; import com.indooratlas.android.sdk.IAOrientationRequest; import com.indooratlas.android.sdk.IAOrientationListener; +import com.indooratlas.android.sdk.IARadioScanRequest; import com.indooratlas.android.sdk.IAWayfindingListener; import com.indooratlas.android.sdk.IAWayfindingRequest; import com.indooratlas.android.sdk.IAGeofence; @@ -63,6 +64,7 @@ public class IALocationPlugin extends CordovaPlugin { private boolean mLocationServiceRunning = false; private IALocationRequest mLocationRequest = IALocationRequest.create(); private IAOrientationRequest mOrientationRequest = new IAOrientationRequest(1.0, 1.0); + private IARadioScanRequest mRadioScanRequest = null; /** * Called by the WebView implementation to check for geolocation permissions, can be used @@ -244,6 +246,14 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo } else if ("lockIndoors".equals(action)) { boolean locked = args.getBoolean(0); lockIndoors(locked); + } else if ("watchIBeacons".equals(action)) { + watchIBeacons(callbackContext); + } else if ("clearIBeaconWatch".equals(action)) { + clearIBeaconWatch(); + } else if ("watchWifis".equals(action)) { + watchWifis(callbackContext); + } else if ("clearWifiWatch".equals(action)) { + clearWifiWatch(); } } catch(Exception ex) { @@ -634,6 +644,78 @@ public void run() { } } + private void watchIBeacons(CallbackContext callbackContext) { + final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.wifis) ? + mRadioScanRequest.andIBeacons() : IARadioScanRequest.withIBeacons(); + mRadioScanRequest = req; + getListener(this).addIBeaconWatch(callbackContext); + cordova.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mLocationManager.requestRadioScanUpdates( + req, + getListener(IALocationPlugin.this) + ); + } + }); + } + + private void clearIBeaconWatch() { + final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.wifis) ? + IARadioScanRequest.withWifis() : null; + mRadioScanRequest = req; + getListener(this).clearIBeaconWatch(); + cordova.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + if (req == null) { + mLocationManager.removeRadioScanUpdates(); + } else { + mLocationManager.requestRadioScanUpdates( + req, + getListener(IALocationPlugin.this) + ); + } + } + }); + } + + private void watchWifis(CallbackContext callbackContext) { + final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.iBeacons) ? + mRadioScanRequest.andWifis() : IARadioScanRequest.withWifis(); + mRadioScanRequest = req; + getListener(this).addWifiWatch(callbackContext); + cordova.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mLocationManager.requestRadioScanUpdates( + req, + getListener(IALocationPlugin.this) + ); + } + }); + } + + private void clearWifiWatch() { + final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.iBeacons) ? + IARadioScanRequest.withIBeacons() : null; + mRadioScanRequest = req; + getListener(this).clearWifiWatch(); + cordova.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + if (req == null) { + mLocationManager.removeRadioScanUpdates(); + } else { + mLocationManager.requestRadioScanUpdates( + req, + getListener(IALocationPlugin.this) + ); + } + } + }); + } + /** * Starts IndoorAtlas positioning session * @param callbackContext diff --git a/src/android/src/main/java/com/ialocation/plugin/IndoorLocationListener.java b/src/android/src/main/java/com/ialocation/plugin/IndoorLocationListener.java index 1aa8713..2ed9622 100644 --- a/src/android/src/main/java/com/ialocation/plugin/IndoorLocationListener.java +++ b/src/android/src/main/java/com/ialocation/plugin/IndoorLocationListener.java @@ -9,6 +9,7 @@ import com.indooratlas.android.sdk.IARegion; import com.indooratlas.android.sdk.IARoute; import com.indooratlas.android.sdk.IAOrientationListener; +import com.indooratlas.android.sdk.IARadioScanListener; import com.indooratlas.android.sdk.IAWayfindingListener; import com.indooratlas.android.sdk.IAGeofence; import com.indooratlas.android.sdk.IAGeofenceEvent; @@ -16,6 +17,7 @@ import com.indooratlas.android.sdk.IAPOI; import com.indooratlas.android.sdk.resources.IAFloorPlan; import com.indooratlas.android.sdk.resources.IALatLng; +import com.indooratlas.android.sdk.resources.IARadioScan; import com.indooratlas.android.sdk.resources.IAVenue; import org.apache.cordova.CallbackContext; @@ -26,11 +28,12 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.List; /** * Handles events from IALocationListener and IARegion.Listener and relays them to Javascript callbacks. */ -public class IndoorLocationListener implements IALocationListener, IARegion.Listener, IAOrientationListener, +public class IndoorLocationListener extends IARadioScanListener implements IALocationListener, IARegion.Listener, IAOrientationListener, IAWayfindingListener, IAGeofenceListener { private static final String TAG = "IndoorLocationListener"; @@ -45,6 +48,8 @@ public class IndoorLocationListener implements IALocationListener, IARegion.List private CallbackContext statusUpdateCallbackContext; private CallbackContext wayfindingUpdateCallbackContext; private CallbackContext geofenceCallbackContext; + private CallbackContext iBeaconScanCallbackContext; + private CallbackContext wifiScanCallbackContext; private ArrayList mCallbacks = new ArrayList(); private CallbackContext mCallbackContext; public IALocation lastKnownLocation = null; @@ -148,6 +153,22 @@ public void removeGeofenceUpdates() { geofenceCallbackContext = null; } + public void addIBeaconWatch(CallbackContext callbackContext) { + iBeaconScanCallbackContext = callbackContext; + } + + public void clearIBeaconWatch() { + iBeaconScanCallbackContext = null; + } + + public void addWifiWatch(CallbackContext callbackContext) { + wifiScanCallbackContext = callbackContext; + } + + public void clearWifiWatch() { + wifiScanCallbackContext = null; + } + /** * Returns the sum of the all callback collections * @return @@ -684,4 +705,99 @@ public void onGeofencesTriggered(IAGeofenceEvent event) { } } } - } + + @Override + public void onIBeaconScan​(List beacons) { + if (iBeaconScanCallbackContext != null) { + try { + JSONArray scans = new JSONArray(); + for (IARadioScan.IBeacon beacon : beacons) { + JSONObject scan = new JSONObject(); + scan.put("uuid", beacon.uuid.toString().toLowerCase()); + scan.put("major", beacon.major); + scan.put("minor", beacon.minor); + scan.put("rssi", beacon.rssi); + scans.put(scan); + } + JSONObject result = new JSONObject(); + result.put("beacons", scans); + PluginResult pluginResult = new PluginResult( + PluginResult.Status.OK, + result + ); + pluginResult.setKeepCallback(true); + iBeaconScanCallbackContext.sendPluginResult(pluginResult); + } catch (JSONException e) { + throw new IllegalStateException(e.getMessage()); + } + } + } + + @Override + public void onIBeaconScanError​(int errorCode, String description) { + if (iBeaconScanCallbackContext != null) { + try { + JSONObject details = new JSONObject(); + details.put("errorCode", errorCode); + JSONObject error = new JSONObject(); + error.put("description", description); + error.put("details", details); + JSONObject result = new JSONObject(); + result.put("error", error); + PluginResult pluginResult = new PluginResult( + PluginResult.Status.OK, + result + ); + pluginResult.setKeepCallback(true); + iBeaconScanCallbackContext.sendPluginResult(pluginResult); + } catch (JSONException e) { + throw new IllegalStateException(e.getMessage()); + } + } + } + + @Override + public void onWifiScan​(List wifis) { + if (wifiScanCallbackContext != null) { + try { + JSONArray scans = new JSONArray(); + for (IARadioScan.Wifi wifi : wifis) { + JSONObject scan = new JSONObject(); + scan.put("bssid", wifi.bssid); + scan.put("rssi", wifi.rssi); + scans.put(scan); + } + JSONObject result = new JSONObject(); + result.put("wifis", scans); + PluginResult pluginResult = new PluginResult( + PluginResult.Status.OK, + result + ); + pluginResult.setKeepCallback(true); + wifiScanCallbackContext.sendPluginResult(pluginResult); + } catch (JSONException e) { + throw new IllegalStateException(e.getMessage()); + } + } + } + + @Override + public void onWifiScanError() { + if (wifiScanCallbackContext != null) { + try { + JSONObject error = new JSONObject(); + error.put("description", "wifi scan failed"); + JSONObject result = new JSONObject(); + result.put("error", error); + PluginResult pluginResult = new PluginResult( + PluginResult.Status.OK, + result + ); + pluginResult.setKeepCallback(true); + wifiScanCallbackContext.sendPluginResult(pluginResult); + } catch (JSONException e) { + throw new IllegalStateException(e.getMessage()); + } + } + } +} diff --git a/src/ios/IndoorAtlasLocationService.h b/src/ios/IndoorAtlasLocationService.h index 4838172..fca75e1 100644 --- a/src/ios/IndoorAtlasLocationService.h +++ b/src/ios/IndoorAtlasLocationService.h @@ -67,6 +67,11 @@ typedef NSUInteger IndoorLocationTransitionType; */ - (void)location:(IndoorAtlasLocationService *)manager didUpdateRoute:(nonnull IARoute *)route; +- (void)location:(IndoorAtlasLocationService *)manager didRangeBeacons:(nonnull NSArray *)beacons; + +- (void)location:(IndoorAtlasLocationService *)manager rangingBeaconsDidFailForRegion:(nonnull CLBeaconRegion *)region + withError:(nonnull NSError *)error; + @end @interface IndoorAtlasLocationService : NSObject{ @@ -129,6 +134,9 @@ typedef NSUInteger IndoorLocationTransitionType; - (void)startMonitoringGeofences:(IAGeofence *)geofence; - (void)stopMonitoringGeofences:(IAGeofence *)geofence; +- (void)startMonitoringForBeacons; +- (void)stopMonitoringForBeacons; + - (void)valueForDistanceFilter:(float *)distance; - (void)valueForTimeFilter:(float *)interval; - (void)setDesiredAccuracy:(ia_location_accuracy)accuracy; diff --git a/src/ios/IndoorAtlasLocationService.m b/src/ios/IndoorAtlasLocationService.m index 1e04e8a..dca3dec 100644 --- a/src/ios/IndoorAtlasLocationService.m +++ b/src/ios/IndoorAtlasLocationService.m @@ -159,6 +159,21 @@ - (void)indoorLocationManager:(IALocationManager *)manager didUpdateRoute:(nonnu } } +- (void)indoorLocationManager:(nonnull IALocationManager *)manager didRangeBeacons:(nonnull NSArray *)beacons +{ + if([self.delegate respondsToSelector:@selector(location:didRangeBeacons:)]) { + [self.delegate location:self didRangeBeacons:beacons]; + } +} + +- (void)indoorLocationManager:(nonnull IALocationManager *)manager rangingBeaconsDidFailForRegion:(nonnull CLBeaconRegion *)region + withError:(nonnull NSError *)error +{ + if([self.delegate respondsToSelector:@selector(location:rangingBeaconsDidFailForRegion:withError:)]) { + [self.delegate location:self rangingBeaconsDidFailForRegion:region withError:error]; + } +} + - (void)valueForDistanceFilter:(float *)distance { self.manager.distanceFilter = (CLLocationDistance) *(distance); @@ -271,4 +286,16 @@ - (void)stopMonitoringGeofences:(IAGeofence *)geofence [self.manager stopMonitoringForGeofence:geofence]; } +- (void)startMonitoringForBeacons +{ + NSLog(@"startMonitoringForBeacons"); + [self.manager startMonitoringForBeacons]; +} + +- (void)stopMonitoringForBeacons +{ + NSLog(@"stopMonitoringForBeacons"); + [self.manager stopMonitoringForBeacons]; +} + @end diff --git a/src/ios/IndoorLocation.h b/src/ios/IndoorLocation.h index 5e479ca..79fe9c6 100644 --- a/src/ios/IndoorLocation.h +++ b/src/ios/IndoorLocation.h @@ -83,4 +83,6 @@ typedef NSUInteger IndoorLocationStatus; - (void)lockFloor:(CDVInvokedUrlCommand *)command; - (void)unlockFloor:(CDVInvokedUrlCommand *)command; - (void)lockIndoors:(CDVInvokedUrlCommand *)command; +- (void)watchIBeacons:(CDVInvokedUrlCommand *)command; +- (void)clearIBeaconWatch:(CDVInvokedUrlCommand *)command; @end diff --git a/src/ios/IndoorLocation.m b/src/ios/IndoorLocation.m index ac916c8..b6c67bf 100644 --- a/src/ios/IndoorLocation.m +++ b/src/ios/IndoorLocation.m @@ -50,6 +50,7 @@ @interface IndoorLocation () { @property (nonatomic, strong) id addStatusUpdateCallbackID; @property (nonatomic, strong) id addRouteUpdateCallbackID; @property (nonatomic, strong) id addGeofenceUpdateCallbackID; +@property (nonatomic, strong) id beaconScanCallbackID; @end @@ -237,6 +238,42 @@ - (void)returnStatusInformation:(NSString *)statusString code:(NSUInteger) code } } +- (void)returnBeaconScans:(NSArray *)beacons +{ + if (self.beaconScanCallbackID != nil) { + NSMutableArray* scans = [[NSMutableArray alloc] init]; + for (int i = 0; i < [beacons count]; i++) { + [scans addObject:[self dictionaryFromCLBeacon:beacons[i]]]; + } + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:1]; + [result setObject:scans forKey:@"beacons"]; + + CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result]; + [pluginResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.beaconScanCallbackID]; + } +} + +- (void)returnBeaconScanError:(CLBeaconRegion *)region + withError:(NSError *)error +{ + if (self.beaconScanCallbackID != nil) { + NSMutableDictionary *details = [NSMutableDictionary dictionaryWithCapacity:1]; + [details setObject:[self dictionaryFromCLBeaconRegion:region] forKey:@"region"]; + + NSMutableDictionary *err = [NSMutableDictionary dictionaryWithCapacity:2]; + [err setObject:[error localizedDescription] forKey:@"description"]; + [err setObject:details forKey:@"details"]; + + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:1]; + [result setObject:err forKey:@"error"]; + + CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result]; + [pluginResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.beaconScanCallbackID]; + } +} + - (NSDictionary *)formatRegionInfo:(IARegion *)regionInfo andTransitionType:(IndoorLocationTransitionType)transitionType { NSMutableDictionary *result = [@{@"regionId": regionInfo.identifier, @@ -720,6 +757,25 @@ - (NSDictionary *)dictionaryFromPoi:(IAPOI *)iaPoi return poi; } +- (NSDictionary *)dictionaryFromCLBeacon:(CLBeacon *)clbeacon +{ + NSMutableDictionary *beacon = [NSMutableDictionary dictionaryWithCapacity:4]; + [beacon setObject:[[[clbeacon proximityUUID] UUIDString] lowercaseString] forKey:@"uuid"]; + [beacon setObject:[clbeacon major] forKey:@"major"]; + [beacon setObject:[clbeacon minor] forKey:@"minor"]; + [beacon setObject:[NSNumber numberWithInteger:[clbeacon rssi]] forKey:@"rssi"]; + return beacon; +} + +- (NSDictionary *)dictionaryFromCLBeaconRegion:(CLBeaconRegion *)region +{ + NSMutableDictionary *beacon = [NSMutableDictionary dictionaryWithCapacity:3]; + [beacon setObject:[[[region proximityUUID] UUIDString] lowercaseString] forKey:@"uuid"]; + [beacon setObject:[region major] forKey:@"major"]; + [beacon setObject:[region minor] forKey:@"minor"]; + return beacon; +} + - (void)watchGeofences:(CDVInvokedUrlCommand *)command { self.addGeofenceUpdateCallbackID = command.callbackId; @@ -763,6 +819,17 @@ - (void)lockIndoors:(CDVInvokedUrlCommand *)command [self.IAlocationInfo lockIndoors:indoors]; } +- (void)watchIBeacons:(CDVInvokedUrlCommand *)command +{ + self.beaconScanCallbackID = command.callbackId; + [self.IAlocationInfo startMonitoringForBeacons]; +} + +- (void)clearIBeaconWatch:(CDVInvokedUrlCommand *)command +{ + [self.IAlocationInfo stopMonitoringForBeacons]; + self.beaconScanCallbackID = nil; +} /** * Create NSMutableDictionary from the RouteLeg object */ @@ -901,6 +968,17 @@ - (void)location:(IndoorAtlasLocationService *)manager didUpdateHeading:(IAHeadi [self returnHeadingInformation:direction timestamp:timestamp]; } +- (void)location:(IndoorAtlasLocationService *)manager didRangeBeacons:(nonnull NSArray *)beacons +{ + [self returnBeaconScans:beacons]; +} + +- (void)location:(IndoorAtlasLocationService *)manager rangingBeaconsDidFailForRegion:(nonnull CLBeaconRegion *)region + withError:(nonnull NSError *)error +{ + [self returnBeaconScanError:region withError:error]; +} + - (void)location:(IndoorAtlasLocationService *)manager statusChanged:(IAStatus *)status { NSString *statusDisplay; diff --git a/www/IndoorAtlas.js b/www/IndoorAtlas.js index f2158eb..be69728 100644 --- a/www/IndoorAtlas.js +++ b/www/IndoorAtlas.js @@ -50,6 +50,9 @@ var CurrentStatus = require('./CurrentStatus'); var Orientation = require('./Orientation'); var Route = require('./Route'); var Geofence = require('./Geofence'); +var IBeacon = require('./RadioScan').IBeacon; +var Wifi = require('./RadioScan').Wifi; +var RadioScanError = require('./RadioScan').RadioScanError; // --- Helper functions and constants (*not* in the global scope) @@ -224,6 +227,10 @@ function IndoorAtlas() { native('removeHeadingCallback', []); native('removeStatusCallback', []); native('removeWayfindingUpdates', []); // just in case + native('clearIBeaconWatch', []); + if (getDeviceType() === 'Android') { + native('clearWifiWatch', []); + } positioningOptions = null; orientationFilter = null; @@ -233,6 +240,39 @@ function IndoorAtlas() { floorLock = null; } + function watchIBeacons() { + native('watchIBeacons', [], function (scan) { + if (callbacks.onIBeaconScan) { + if (scan.error) callbacks.onIBeaconScan(new RadioScanError(scan.error), undefined); + else callbacks.onIBeaconScan(undefined, scan.beacons.map(function(beacon) { return new IBeacon(beacon); })); + } + }); + } + + function clearIBeaconWatch() { + native('clearIBeaconWatch', []); + } + + function watchWifis() { + if (getDeviceType() !== 'Android') { + if (debug) debug('Wifi scan callback only available on Android'); + return; + } + native('watchWifis', [], function (scan) { + if (callbacks.onWifiScan) { + if (scan.error) callbacks.onWifiScan(new RadioScanError(scan.error), undefined); + else callbacks.onWifiScan(undefined, scan.wifis.map(function(wifi) { return new Wifi(wifi); })); + } + }); + } + + function clearWifiWatch() { + if (getDeviceType() !== 'Android') { + return; + } + native('clearWifiWatch', []); + } + // ################ PUBLIC API ################ // --- Error and status reporting @@ -289,6 +329,9 @@ function IndoorAtlas() { if (callbacks.onLocation) startPositioning(); if (callbacks.onTriggeredGeofence) requestGeofenceUpdates(); + + if (callbacks.onIBeaconScan) watchIBeacons(); + if (callbacks.onWifiScan) watchWifis(); } var config = [apiKey, 'dummy-secret']; @@ -740,6 +783,108 @@ function IndoorAtlas() { } return self; }; + + // --- Radio scans + + /** + * Callback function triggered on beacon scans. Only one callback can be active at a time. + * + * NOTE! To enable the callback, please contact IndoorAtlas support. + * + * @callback iBeaconScanCallback + * @param {RadioScanError} error or undefined if no error + * @param {IBeacon[]} list of scanned beacons or undefined if there was error + */ + + /** + * Start observing beacon scans. + * + * NOTE! To enable the callback, please contact IndoorAtlas support. + * + * @param {function(iBeaconScanCallback)} onIBeaconScan a callback that executes + * whenever IA SDK internally scans beacons. + * @return {object} returns `this` to allow chaining + * @example + * IndoorAtlas.watchIBeacons((error, beacons) => { + * if (error) { + * console.log(`error scanning beacons: ${error.description} details: ${JSON.stringify(error.details)}`); + * } else { + * console.log(`scanned beacon count: ${beacons.length}`); + * } + * }); + */ + this.watchIBeacons = function(onIBeaconScan) { + if (callbacks.onIBeaconScan) { + warning('Overwriting existing beacons watch'); + } + callbacks.onIBeaconScan = onIBeaconScan; + if (initialized) { + watchIBeacons(); + } + return self; + }; + /** + * Stop observing beacon scans. + * + * @return {object} returns `this` to allow chaining + */ + this.clearIBeaconWatch = function() { + delete callbacks.onIBeaconScan; + if (initialized) { + clearIBeaconWatch(); + } + return self; + }; + + /** + * Callback function triggered on wifi scans. Only one callback can be active at a time. + * + * NOTE! To enable the callback, please contact IndoorAtlas support. + * + * @callback wifiScanCallback + * @param {RadioScanError} error or undefined if no error + * @param {Wifi[]} list of scanned wifis or undefined if there was error + */ + + /** + * Start observing wifi scans. Only supported on Android. + * + * NOTE! To enable the callback, please contact IndoorAtlas support. + * + * @param {function(wifiScanCallback)} onWifiScan a callback that executes + * whenever IA SDK internally scans wifis. + * @return {object} returns `this` to allow chaining + * @example + * IndoorAtlas.watchWifis((error, wifis) => { + * if (error) { + * console.log(`error scanning wifis: ${error.description}`); + * } else { + * console.log(`scanned wifi count: ${wifis.length}`); + * } + * }); + */ + this.watchWifis = function(onWifiScan) { + if (callbacks.onWifiScan) { + warning('Overwriting existing wifis watch'); + } + callbacks.onWifiScan = onWifiScan; + if (initialized) { + watchWifis(); + } + return self; + }; + /** + * Stop observing wifi scans. + * + * @return {object} returns `this` to allow chaining + */ + this.clearWifiWatch = function() { + delete callbacks.onWifiScan; + if (initialized) { + clearWifiWatch(); + } + return self; + }; } module.exports = new IndoorAtlas(); diff --git a/www/RadioScan.js b/www/RadioScan.js new file mode 100644 index 0000000..6ac9e22 --- /dev/null +++ b/www/RadioScan.js @@ -0,0 +1,62 @@ +/** + * IBeacon + */ +var IBeacon = function(beacon) { + /** + * UUID + * @type {string} + */ + this.uuid = beacon.uuid; + /** + * Major + * @type {number} + */ + this.major = beacon.major; + /** + * Minor + * @type {number} + */ + this.minor = beacon.minor; + /** + * RSSI - the detected signal level in dBm + * @type {number} + */ + this.rssi = beacon.rssi; +}; + +/** + * Wifi + */ +var Wifi = function(wifi) { + /** + * BSSID + * @type {string} + */ + this.bssid = wifi.bssid; + /** + * RSSI - the detected signal level in dBm + * @type {number} + */ + this.rssi = wifi.rssi; +}; + +/** + * Error + */ +var RadioScanError = function(error) { + /** + * Error description + * @type {string} + */ + this.description = error.description; + /** + * Error details (optional). Platform specific error details for failed scan (if available). + * Examples: + * iOS: `{ "region": {"uuid": "e913d904-8b75-4d3c-b3e0-b6e98feae1c7", "major": 1, "minor": 2} }` + * Android: `{ "errorCode": 2 }` + * @type {object} + */ + this.details = error.details; +}; + +module.exports = { IBeacon, Wifi, RadioScanError }; From eb1eca1ea4dc6b8790cddb603824217381b161dc Mon Sep 17 00:00:00 2001 From: Matti Tiainen Date: Mon, 13 May 2024 17:03:50 +0300 Subject: [PATCH 2/2] Bump version to 3.6.6 --- CHANGELOG.md | 5 +++++ package.json | 2 +- plugin.xml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3da56a..be233f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +Version 3.6.6 - May 2024 +---------------- + * Add `NSMotionUsageDescription` declaration for iOS + * Add radio scan callbacks API (NOTE! To enable the callbacks, please contact IndoorAtlas support) + Version 3.6.5 - May 2024 ---------------- * Fixed compile on iOS diff --git a/package.json b/package.json index 316a4cc..0d866b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-indooratlas", - "version": "3.6.5", + "version": "3.6.6", "description": "Cordova plugin using IndoorAtlas SDK.", "cordova": { "id": "cordova-plugin-indooratlas", diff --git a/plugin.xml b/plugin.xml index ad3aa13..12ba5cf 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,7 +1,7 @@ + version="3.6.6"> IndoorAtlas IndoorAtlas Cordova Plugin.