From e84100fca5a5b34d5561c59a073a8503c01bdf71 Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 16 Mar 2014 14:27:31 +0000 Subject: [PATCH] Version 0.1.0, initial commit with the basic functionality. --- .gitignore | 23 ++++ LICENSE | 202 +++++++++++++++++++++++++++++++++ README.md | 23 ++++ RELEASENOTES.md | 24 ++++ plugin.xml | 27 +++++ src/ios/CDVIBeacon.h | 40 +++++++ src/ios/CDVIBeacon.m | 264 +++++++++++++++++++++++++++++++++++++++++++ www/ibeacon.js | 234 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 837 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 RELEASENOTES.md create mode 100644 plugin.xml create mode 100644 src/ios/CDVIBeacon.h create mode 100644 src/ios/CDVIBeacon.m create mode 100644 www/ibeacon.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52b558e --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +#If ignorance is bliss, then somebody knock the smile off my face + +*.csproj.user +*.suo +*.cache +Thumbs.db +*.DS_Store + +*.bak +*.cache +*.log +*.swp +*.user + + + + + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3567b8e --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ + + +# com.mippin.cordova.ibeacon + + +TODO diff --git a/RELEASENOTES.md b/RELEASENOTES.md new file mode 100644 index 0000000..39ec30a --- /dev/null +++ b/RELEASENOTES.md @@ -0,0 +1,24 @@ + +# Release Notes + +### 0.1.0 (14.02.2014) +* Beta version created. diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..2313ba8 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,27 @@ + + + + iBeacon + Cordova iBeacon Plugin + Apache 2.0 + cordova,ibeacon,beacon,bluetooth,le + https://github.com/petermetz/cordova-plugin-ibeacon.git + + + + + + + + + + + + + + + + + diff --git a/src/ios/CDVIBeacon.h b/src/ios/CDVIBeacon.h new file mode 100644 index 0000000..61b9fd7 --- /dev/null +++ b/src/ios/CDVIBeacon.h @@ -0,0 +1,40 @@ + +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +// +// CDVPluginIBeacon.h +// +// Created by Peter Metz on 19/02/2014. +// +// + +#import +#import + +@interface CDVPluginIBeacon : CDVPlugin + +- (void)startMonitoringForRegion: (CDVInvokedUrlCommand*)command; +- (void)stopMonitoringForRegion: (CDVInvokedUrlCommand*)command; +- (void)startRangingBeaconsInRegion: (CDVInvokedUrlCommand*)command; +- (void)stopRangingBeaconsInRegion: (CDVInvokedUrlCommand*)command; + +- (CLBeaconRegion *) parse :(NSDictionary*) regionArguments; + +@end diff --git a/src/ios/CDVIBeacon.m b/src/ios/CDVIBeacon.m new file mode 100644 index 0000000..57ec504 --- /dev/null +++ b/src/ios/CDVIBeacon.m @@ -0,0 +1,264 @@ + +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + + +// +// CDVPluginIBeacon.m +// +// Created by Peter Metz on 19/02/2014. +// +// + +#import "CDVPluginIBeacon.h" + +@implementation CDVPluginIBeacon +{ + NSString *monitoringCallbackId; + NSString *rangingCallbackId; + CLLocationManager *_locationManager; +} + + +- (void)pluginInitialize +{ + NSLog(@"[IBeacon Plugin] pluginInitialize()"); + + _locationManager = [[CLLocationManager alloc] init]; + _locationManager.delegate = self; + + // You can listen to more app notifications, see: + // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4 + + // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler + + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; + + // Added in 2.3.0 + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil]; + + // Added in 2.5.0 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView]; +} + +- (NSString*) nameOfRegionState:(CLRegionState)state { + switch (state) { + case CLRegionStateInside: + return @"CLRegionStateInside"; + break; + case CLRegionStateOutside: + return @"CLRegionStateOutside"; + case CLRegionStateUnknown: + return @"CLRegionStateUnknown"; + default: + return @"ErrorUnknownCLRegionStateObjectReceived"; + break; + } +} + +- (NSDictionary*) mapOfRegion: (CLRegion*) region { + NSMutableDictionary* dict; + + if ([region isKindOfClass:[CLBeaconRegion class]]) { + CLBeaconRegion* beaconRegion = (CLBeaconRegion*) region; + dict = [[NSMutableDictionary alloc] initWithDictionary:[self mapOfBeaconRegion:beaconRegion]]; + } else { + dict = [[NSMutableDictionary alloc] init]; + } + + // identifier + [dict setObject:region.identifier forKey:@"identifier"]; + + // radius + NSNumber* radius = [[NSNumber alloc] initWithDouble:region.radius ]; + [dict setObject:radius forKey:@"radius"]; + CLLocationCoordinate2D coordinates; + + // center + NSDictionary* coordinatesMap = [[NSMutableDictionary alloc]initWithCapacity:2]; + [coordinatesMap setValue:[[NSNumber alloc] initWithDouble: coordinates.latitude] forKey:@"latitude"]; + [coordinatesMap setValue:[[NSNumber alloc] initWithDouble: coordinates.longitude] forKey:@"longitude"]; + [dict setObject:coordinatesMap forKey:@"center"]; + + + return dict; +} + +- (NSDictionary*) mapOfBeaconRegion: (CLBeaconRegion*) region { + + NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; + [dict setObject:region.proximityUUID.UUIDString forKey:@"uuid"]; + [dict setObject:region.major forKey:@"major"]; + [dict setObject:region.minor forKey:@"minor"]; + + + return dict; +} + +- (NSDictionary*) mapOfBeacon: (CLBeacon*) beacon { + NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; + + // uuid + NSString* uuid = beacon.proximityUUID.UUIDString; + [dict setObject:uuid forKey:@"uuid"]; + + // proximity + CLProximity proximity = beacon.proximity; + NSString* proximityString = [self nameOfProximity:proximity]; + [dict setObject:proximityString forKey:@"proximity"]; + + // major + [dict setObject:beacon.major forKey:@"major"]; + + // minor + [dict setObject:beacon.minor forKey:@"minor"]; + + // rssi + NSNumber * rssi = [[NSNumber alloc] initWithInteger:beacon.rssi]; + [dict setObject:rssi forKey:@"rssi"]; + + return dict; +} + +- (NSString*) nameOfProximity: (CLProximity) proximity { + switch (proximity) { + case CLProximityNear: + return @"CLProximityNear"; + break; + case CLProximityFar: + return @"CLProximityFar"; + case CLProximityImmediate: + return @"CLProximityImmediate"; + case CLProximityUnknown: + return @"CLProximityUnknown"; + default: + return @"ErrorProximityValueUnknown"; + break; + } +} + +- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region +{ + if(state == CLRegionStateInside) { + NSLog(@"[IBeacon Plugin] didDetermineState INSIDE for %@", region.identifier); + } + else if(state == CLRegionStateOutside) { + NSLog(@"[IBeacon Plugin] didDetermineState OUTSIDE for %@", region.identifier); + } + else { + NSLog(@"[IBeacon Plugin] didDetermineState OTHER for %@", region.identifier); + } + + NSLog(@"[IBeacon Plugin] Sending plugin callback with callbackId: %@", monitoringCallbackId); + + [self.commandDelegate runInBackground:^{ + NSMutableDictionary* callbackData = [[NSMutableDictionary alloc]init]; + [callbackData setObject:@"HELLO WORLD I JUST DETERMINED THE STATE OF A BEACON" forKey:@"result"]; + [callbackData setObject:[self mapOfRegion:region] forKey:@"region"]; + [callbackData setObject:[self nameOfRegionState:state] forKey:@"state"]; + + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:callbackData]; + [pluginResult setKeepCallbackAsBool:YES]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:monitoringCallbackId]; + }]; +} + +- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region +{ + NSLog(@"[IBeacon Plugin] didRangeBeacons() Beacons:"); + for (CLBeacon* beacon in beacons) { + NSLog(@"[IBeacon Plugin] didRangeBeacons() Description: %@, proximity: %d, proximityUUID: %@, major: %@, minor: %@", beacon.description, beacon.proximity, beacon.proximityUUID, beacon.major, beacon.minor); + } + + NSLog(@"[IBeacon Plugin] Sending plugin callback with callbackId: %@", rangingCallbackId); + NSMutableArray* beaconsMapsArray = [[NSMutableArray alloc] init]; + for (CLBeacon* beacon in beacons) { + NSDictionary* dictOfBeacon = [self mapOfBeacon:beacon]; + [beaconsMapsArray addObject:dictOfBeacon]; + } + + [self.commandDelegate runInBackground:^{ + NSMutableDictionary* callbackData = [[NSMutableDictionary alloc]init]; + [callbackData setObject:[self mapOfRegion:region] forKey:@"region"]; + [callbackData setObject:beaconsMapsArray forKey:@"beacons"]; + + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:callbackData]; + [pluginResult setKeepCallbackAsBool:YES]; + + [self.commandDelegate sendPluginResult:pluginResult callbackId:rangingCallbackId]; + }]; +} + + +- (void)startMonitoringForRegion: (CDVInvokedUrlCommand*)command { + NSLog(@"[IBeacon Plugin] startMonitoringForRegion() %@", command.arguments); + CLBeaconRegion* beaconRegion = [self parse:[command.arguments objectAtIndex: 0]]; + monitoringCallbackId = command.callbackId; + [_locationManager startMonitoringForRegion:beaconRegion]; + NSLog(@"[IBeacon Plugin] started monitoring successfully."); +} + +- (void)stopMonitoringForRegion: (CDVInvokedUrlCommand*)command { + NSLog(@"[IBeacon Plugin] stopMonitoringForRegion() %@", command.arguments); + CLBeaconRegion* beaconRegion = [self parse:[command.arguments objectAtIndex: 0]]; + [_locationManager stopMonitoringForRegion:beaconRegion]; + NSLog(@"[IBeacon Plugin] stopped monitoring successfully."); +} + +- (void)startRangingBeaconsInRegion: (CDVInvokedUrlCommand*)command { + NSLog(@"[IBeacon Plugin] startRangingBeaconsInRegion() %@", command.arguments); + CLBeaconRegion* beaconRegion = [self parse:[command.arguments objectAtIndex: 0]]; + rangingCallbackId = command.callbackId; + [_locationManager startRangingBeaconsInRegion:NULL]; + NSLog(@"[IBeacon Plugin] Started ranging successfully."); +} + +- (void)stopRangingBeaconsInRegion: (CDVInvokedUrlCommand*)command { + NSLog(@"[IBeacon Plugin] stopRangingBeaconsInRegion() %@", command.arguments); + CLBeaconRegion* beaconRegion = [self parse:[command.arguments objectAtIndex: 0]]; + [_locationManager stopRangingBeaconsInRegion:beaconRegion]; + NSLog(@"[IBeacon Plugin] Stopped ranging successfully."); +} + +- (void) pageDidLoad: (NSNotification*)notification{ + NSLog(@"[IBeacon Plugin] pageDidLoad()"); +} + +- (CLBeaconRegion *) parse :(NSDictionary*) regionArguments { + + NSString* uuidString = [regionArguments objectForKey:@"uuid"]; + NSUUID* uuid = [[NSUUID alloc] initWithUUIDString:uuidString]; + int major = [[regionArguments objectForKey:@"major"] intValue]; + int minor = [[regionArguments objectForKey:@"minor"] intValue]; + NSString* identifier = [regionArguments objectForKey:@"identifier"]; + BOOL notifyEntryStateOnDisplay = [[regionArguments objectForKey:@"notifyEntryStateOnDisplay"] boolValue]; + + CLBeaconRegion *beaconRegion; + NSLog(@"[IBeacon Plugin] Creating Beacon with parameters uuid: %@, major: %i, minor: %i, identifier: %@", uuid, major, minor, identifier); + beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major: major minor: minor identifier: identifier]; + beaconRegion.notifyEntryStateOnDisplay = notifyEntryStateOnDisplay; + NSLog(@"[IBeacon Plugin] Parsed CLBeaconRegion successfully: %@", beaconRegion.debugDescription); + return beaconRegion; +} +@end + diff --git a/www/ibeacon.js b/www/ibeacon.js new file mode 100644 index 0000000..2406b4e --- /dev/null +++ b/www/ibeacon.js @@ -0,0 +1,234 @@ +cordova.define("com.mippin.cordova.ibeacon", function(require, exports, module) {/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ + +var exec = require('cordova/exec'); + +/** + * This represents the CLLocationManager's API (only the iBeacon related functions added in iOS 7). + * + * @constructor + */ +function IBeacon() { +} + +IBeacon.prototype.isCLBeaconRegion = function (object) { + return (object instanceof CLBeaconRegion); +}; + +IBeacon.prototype.validateRegion = function (regionObject) { + if (!this.isCLBeaconRegion(regionObject)) { + throw new TypeError('Parameter region has to be a CLBeaconRegion object.'); + } + regionObject.validateFields(); // ensures fields are not empty +} + +IBeacon.prototype.isArrayOfBeacons = function (array) { + if (!array || typeof(array.length) !== 'number') { + return false; + } + + for (var i = 0; i < array.length; i++) { + var beacon = array[i]; + if (!(beacon instanceof IBeacon.CLBeaconRegion)) { + return false; + } + }; +}; + +IBeacon.prototype.validateRegionArray = function (regionArray) { + if (!this.isArrayOfBeacons(regionArray)) { + throw new TypeError('The regions parameter is mandatory and has to be an Array of IBeacon.CLBeaconRegion objects.'); + } +}; + +/** + * Common function to interact with the Objective C Runtime through the Cordova Plugin + * API. + * + * @param actionName: The method name to call in the native implementaiton. + * @param region: A CLBeaconRegion instance, to adminster. + * @param beaconCallback: This will be called by the native layer when an update + * is triggered by the OS. + */ +IBeacon.prototype.callObjCRuntime = function (actionName, region, beaconCallback, errorCallback) { + this.validateRegion(region); + + var validActions = ['startMonitoringForRegion', 'stopMonitoringForRegion', 'startRangingBeaconsInRegion', 'stopRangingBeaconsInRegion']; + + if (validActions.indexOf(actionName) < 0) { + throw new Error('Invalid operation: ' + actionName + ' Valid ones are: ' + validActions.join(',')); + } + + var onSuccess = function (result) { + if (beaconCallback) { + beaconCallback(result); + } else { + console.error('There is no callback to call with ', result); + } + }; + var onFailure = function (error) { + if (errorCallback) { + errorCallback(error); + } else { + console.error('There was en error in the beacon registration process: ' + JSON.stringify(error)); + } + }; + + exec(onSuccess, onFailure, "IBeacon", actionName, [region]); +}; + +IBeacon.prototype.startMonitoringForRegion = function (region, didDetermineStateCallback) { + return this.callObjCRuntime('startMonitoringForRegion', region, didDetermineStateCallback); +}; + +/** + * A simple wrapper around {#startMonitoringForRegion()} to make it possible to start monitoring + * multiple beacons with a single call. + * + * @param regions Array of IBeacon.CLBeaconRegion objects to monitor. + * @param didDetermineStateCallback: The function to call when any of the passed CLBeaconRegion + * objects were captured on the native layer. + * + */ +IBeacon.prototype.startMonitoringForRegions = function (regions, didDetermineStateCallback) { + this.validateRegionArray(regions); + + for (var i = 0; i < regions.length; i++) { + var beacon = regions[i]; + this.callObjCRuntime('startMonitoringForRegion', region, didDetermineStateCallback); + } +}; + +IBeacon.prototype.stopMonitoringForRegion = function (region) { + this.validateRegion(region); + return this.callObjCRuntime('stopMonitoringForRegion', region); +}; + +/** + * A simple wrapper around {#startRangingBeaconsInRegion()} to make it possible to start ranging + * multiple beacons with a single call. + * + * @param regions Array of IBeacon.CLBeaconRegion objects to range. + * @param didRangeBeaconsCallback: The function to call when any of the passed CLBeaconRegion + * objects were captured on the native layer. + * + */ +IBeacon.prototype.startRangingBeaconsInRegions = function (regions, didRangeBeaconsCallback) { + this.validateRegionArray(regions); + + for (var i = 0; i < regions.length; i++) { + var beacon = regions[i]; + this.callObjCRuntime('startRangingBeaconsInRegion', region, didRangeBeaconsCallback); + } +}; + +IBeacon.prototype.startRangingBeaconsInRegion = function (region, didRangeBeaconsCallback) { + this.validateRegion(region); + return this.callObjCRuntime('startRangingBeaconsInRegion', region, didRangeBeaconsCallback); +}; + +IBeacon.prototype.stopRangingBeaconsInRegion = function (region) { + this.validateRegion(region); + return this.callObjCRuntime('stopRangingBeaconsInRegion', region); +}; + +/** + * Stops ranging an array of IBeacon.CLBeaconRegion objects. + * A short-hand wrapper around {#stopRangingBeaconsInRegion} + * + * @param regions: An array of CLBeaconRegion objects. + * @throws: TypeError if the regions parameter is not an array of + * objects which are all instances of the CLBeaconRegion prototype. + * + */ +IBeacon.prototype.stopRangingBeaconsInRegions = function (regions) { + this.validateRegionArray(regions); + for (var i = Things.length - 1; i >= 0; i--) { + Things[i] + }; + return this.callObjCRuntime('stopRangingBeaconsInRegion', region); +}; + + +function isBlank(str) { + return (!str || /^\s*$/.test(str)); +} + + +/** + * A model class which mimics the CLBeaconRegion class from the native iOS SDK. + * + * Used to validate the input fields in a more fashioned + * way than checking JSON objects' keys in the plugin's code. + * + * Also the client code should feel better to write instead of hacking together the + * random JSON objects. + * + * @param notifyEntryStateOnDisplay: + * + */ +var CLBeaconRegion = function(uuid, major, minor, identifier, notifyEntryStateOnDisplay) { + this.uuid = uuid; + this.major = major; + this.minor = minor; + this.identifier = identifier; + this.notifyEntryStateOnDisplay = true; + + if (typeof(notifyEntryStateOnDisplay) === 'Boolean') { + this.notifyEntryStateOnDisplay = notifyEntryStateOnDisplay; + } else { + this.notifyEntryStateOnDisplay = true; + } + + this.validateFields(); + +}; + +CLBeaconRegion.prototype.validateFields = function () { + // Parameter uuid + if (isBlank(this.uuid)) { + throw new TypeError('Parameter uuid has to be a String.'); + } + + // Parameter major + var majorInt = parseInt(this.major); + if (majorInt !== this.major || majorInt === NaN) { + throw new TypeError('Parameter major has to be an integer.'); + } + + // Parameter minor + var minorInt = parseInt(this.minor); + if (minorInt !== this.minor || minorInt === NaN) { + throw new TypeError('Parameter minor has to be an integer.'); + } + + // Parameter identifier + if (isBlank(this.identifier)) { + throw new TypeError('Parameter identifier has to be a String.'); + } +}; + +IBeacon.prototype.CLBeaconRegion = CLBeaconRegion; + + +module.exports = new IBeacon(); + +});