diff --git a/ReactNativeBeaconsManager.podspec b/ReactNativeBeaconsManager.podspec new file mode 100644 index 00000000..eae63a0b --- /dev/null +++ b/ReactNativeBeaconsManager.podspec @@ -0,0 +1,11 @@ +Pod::Spec.new do |s| + s.name = "ReactNativeBeaconsManager" + s.version = "1.0.8" + s.summary = "React-Native library for detecting beacons (iOS and Android)" + s.homepage = "https://github.com/MacKentoch/react-native-beacons-manager#readme" + s.license = { :type => "MIT" } + s.authors = { "" => "" } + s.platform = :ios, "8.0" + s.source = { :path => "." } + s.source_files = "ios", "ios/**/*.{h,m}" +end \ No newline at end of file diff --git a/examples/BeaconsDemo/index.ios.js b/examples/BeaconsDemo/index.ios.js index 50eb022b..f58a026d 100644 --- a/examples/BeaconsDemo/index.ios.js +++ b/examples/BeaconsDemo/index.ios.js @@ -76,6 +76,7 @@ class BeaconsDemo extends Component { // you also have to add "Privacy - Location Always Usage Description" in your "Info.plist" file // otherwise monitoring won't work Beacons.requestAlwaysAuthorization(); + Beacons.shouldDropEmptyRanges(true); // Define a region which can be identifier + uuid, // identifier + uuid + major or identifier + uuid + major + minor // (minor and major properties are numbers) diff --git a/examples/samples/ranging.ios.js b/examples/samples/ranging.ios.js index 02f35eba..7df91e45 100644 --- a/examples/samples/ranging.ios.js +++ b/examples/samples/ranging.ios.js @@ -1,4 +1,5 @@ +import { NativeEventEmitter } from 'react-native' import Beacons from 'react-native-beacons-manager'; import moment from 'moment'; @@ -8,6 +9,10 @@ class beaconRangingOnly extends Component { constructor(props) { super(props); + this.beaconsEmitter = new NativeEventEmitter(Beacons); + this.beaconsDidRangeEvent = null; + this.authStateDidRangeEvent = null; + this.state = { // region information uuid: '7b44b47b-52a1-5381-90c2-f09b6838c5d4', @@ -24,7 +29,7 @@ class beaconRangingOnly extends Component { // // OPTIONAL: listen to authorization change - DeviceEventEmitter.addListener( + this.authStateDidRangeEvent = this.beaconsEmitter.addListener( 'authorizationStatusDidChange', (info) => console.log('authorizationStatusDidChange: ', info) ); @@ -47,7 +52,7 @@ class beaconRangingOnly extends Component { // // Ranging: Listen for beacon changes - DeviceEventEmitter.addListener( + this.beaconsDidRangeEvent = this.beaconsEmitter.addListener( 'beaconsDidRange', (data) => { // console.log('beaconsDidRange data: ', data); @@ -62,7 +67,8 @@ class beaconRangingOnly extends Component { // stop ranging beacons: Beacons.stopRangingBeaconsInRegion(region); // remove beacons event we registered at componentDidMount - DeviceEventEmitter.removeListener('beaconsDidRange'); + this.beaconsDidRangeEvent.remove(); + this.authStateDidRangeEvent.remove(); } render() { diff --git a/ios/RNiBeacon/RNiBeacon/RNiBeacon.h b/ios/RNiBeacon/RNiBeacon/RNiBeacon.h index d08cac98..f85560f1 100644 --- a/ios/RNiBeacon/RNiBeacon/RNiBeacon.h +++ b/ios/RNiBeacon/RNiBeacon/RNiBeacon.h @@ -7,8 +7,10 @@ // #import + #import +#import -@interface RNiBeacon : NSObject +@interface RNiBeacon : RCTEventEmitter @end diff --git a/ios/RNiBeacon/RNiBeacon/RNiBeacon.m b/ios/RNiBeacon/RNiBeacon/RNiBeacon.m index d91b6b03..42e7f872 100644 --- a/ios/RNiBeacon/RNiBeacon/RNiBeacon.m +++ b/ios/RNiBeacon/RNiBeacon/RNiBeacon.m @@ -25,8 +25,6 @@ @implementation RNiBeacon RCT_EXPORT_MODULE() -@synthesize bridge = _bridge; - #pragma mark Initialization - (instancetype)init @@ -42,6 +40,17 @@ - (instancetype)init return self; } +- (NSArray *)supportedEvents +{ + return @[ + @"authorizationStatusDidChange", + @"beaconsDidRange", + @"regionDidEnter", + @"regionDidExit", + @"didDetermineState" + ]; +} + #pragma mark -(CLBeaconRegion *) createBeaconRegion: (NSString *) identifier @@ -207,8 +216,8 @@ -(NSString *)nameForAuthorizationStatus:(CLAuthorizationStatus)authorizationStat -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { - NSString *statusName = [self nameForAuthorizationStatus:status]; - [self.bridge.eventDispatcher sendDeviceEventWithName:@"authorizationStatusDidChange" body:statusName]; + NSString *statusName = [self nameForAuthorizationStatus:status]; + [self sendEventWithName:@"authorizationStatusDidChange" body:statusName]; } -(void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error @@ -224,6 +233,25 @@ -(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *) NSLog(@"Location manager failed: %@", error); } +-(NSString *)stringForState:(CLRegionState)state { + switch (state) { + case CLRegionStateInside: return @"inside"; + case CLRegionStateOutside: return @"outside"; + case CLRegionStateUnknown: return @"unknown"; + default: return @"unknown"; + } +} + +- (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region +{ + NSDictionary *event = @{ + @"state": [self stringForState:state], + @"identifier": region.identifier, + }; + + [self sendEventWithName:@"didDetermineState" body:event]; +} + -(void) locationManager:(CLLocationManager *)manager didRangeBeacons: (NSArray *)beacons inRegion:(CLBeaconRegion *)region { @@ -252,7 +280,7 @@ -(void) locationManager:(CLLocationManager *)manager didRangeBeacons: @"beacons": beaconArray }; - [self.bridge.eventDispatcher sendDeviceEventWithName:@"beaconsDidRange" body:event]; + [self sendEventWithName:@"beaconsDidRange" body:event]; } -(void)locationManager:(CLLocationManager *)manager @@ -262,7 +290,7 @@ -(void)locationManager:(CLLocationManager *)manager @"uuid": [region.proximityUUID UUIDString], }; - [self.bridge.eventDispatcher sendDeviceEventWithName:@"regionDidEnter" body:event]; + [self sendEventWithName:@"regionDidEnter" body:event]; } -(void)locationManager:(CLLocationManager *)manager @@ -272,7 +300,7 @@ -(void)locationManager:(CLLocationManager *)manager @"uuid": [region.proximityUUID UUIDString], }; - [self.bridge.eventDispatcher sendDeviceEventWithName:@"regionDidExit" body:event]; + [self sendEventWithName:@"regionDidExit" body:event]; } diff --git a/lib/module.android.js b/lib/module.android.js deleted file mode 100644 index cdfdfb25..00000000 --- a/lib/module.android.js +++ /dev/null @@ -1,231 +0,0 @@ -// @flow - -const RN = require('react-native'); - -const beaconsAndroid: any = RN.NativeModules.BeaconsAndroidModule; - -const PARSER_IBEACON: string = 'm:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24'; -const PARSER_ESTIMOTE: string = 'm:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24'; -const ALTBEACON: string = 'm:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25'; -const EDDYSTONE_TLM: string = 'x,s:0-1=feaa,m:2-2=20,d:3-3,d:4-5,d:6-7,d:8-11,d:12-15'; -const EDDYSTONE_UID: string = 's:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19'; -const EDDYSTONE_URL: string = 's:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v'; - -const tramissionSupport: Array = [ - 'SUPPORTED', - 'NOT_SUPPORTED_MIN_SDK', - 'NOT_SUPPORTED_BLE', - 'DEPRECATED_NOT_SUPPORTED_MULTIPLE_ADVERTISEMENTS', - 'NOT_SUPPORTED_CANNOT_GET_ADVERTISER', - 'NOT_SUPPORTED_CANNOT_GET_ADVERTISER_MULTIPLE_ADVERTISEMENTS' -]; - -const ARMA_RSSI_FILTER = beaconsAndroid.ARMA_RSSI_FILTER; -const RUNNING_AVG_RSSI_FILTER = beaconsAndroid.RUNNING_AVG_RSSI_FILTER; - -function setHardwareEqualityEnforced(e: boolean): void { - beaconsAndroid.setHardwareEqualityEnforced(e); -} - -/** - * set beacon layout for iBeacon - * - */ -function detectIBeacons(): void { - beaconsAndroid.addParser(PARSER_IBEACON); -} - -/** -* set beacon layout for alBeacon -* -*/ -function detectAltBeacons(): void { - beaconsAndroid.addParser(ALTBEACON); -} - -/** -* set beacon layout for estimote -* -*/ -function detectEstimotes(): void { - beaconsAndroid.addParser(PARSER_ESTIMOTE); -} - -/** -* set beacon layout for eddystone UID -* -*/ -function detectEddystoneUID(): void { - beaconsAndroid.addParser(EDDYSTONE_UID); -} - -/** -* set beacon layout for eddystone URL -* -*/ -function detectEddystoneURL(): void { - beaconsAndroid.addParser(EDDYSTONE_URL); -} - -/** -* set beacon layout for eddystone TLM -* -*/ -function detectEddystoneTLM(): void { - beaconsAndroid.addParser(EDDYSTONE_TLM); -} - -/** -* set beacon for custom layout -* -*/ -function detectCustomBeaconLayout(parser: number): void { - beaconsAndroid.addParser(parser); -} - -function setBackgroundScanPeriod(period: number): void { - beaconsAndroid.setBackgroundScanPeriod(period); -} - -function setBackgroundBetweenScanPeriod(period: number): void { - beaconsAndroid.setBackgroundBetweenScanPeriod(period); -} - -function setForegroundScanPeriod(period: number): void { - beaconsAndroid.setForegroundScanPeriod(period); -} - -function setRssiFilter(filterType: number, avgModifier: number): void { - beaconsAndroid.setRssiFilter(filterType, avgModifier); -} - -function getRangedRegions(): Promise { - return new Promise((resolve, reject) => { - beaconsAndroid.getRangedRegions(resolve); - }); -} - -type BeaconRegion = { - identifier: string, - uuid: string, - minor?: number, - major?: number -}; - - -/** - * get monitored regions - * - * @returns {Promise>} promise resolve to an array of monitored regions - */ -function getMonitoredRegions(): Promise> { - return new Promise((resolve, reject) => { - beaconsAndroid.getMonitoredRegions(resolve); - }); -} - -/** - * check if beacon support transmission - * - * @returns {Promise} promise resolve to an integer - */ -function checkTransmissionSupported(): Promise { - return new Promise((resolve, reject) => { - beaconsAndroid.checkTransmissionSupported(status => resolve(tramissionSupport[status])); - }); -} - -/** - * start monitoring for a region - * - * @param {Object: BeaconRegion} region region to monitor (identifier + uuid -> major and minor are optional) - * @returns {Promise} promise resolves to void or error - */ -function startMonitoringForRegion(region: BeaconRegion): Promise { - return new Promise((resolve, reject) => { - // NOTE: major and minor are optional values: if user don't assign them we have to send a null value (not undefined): - beaconsAndroid.startMonitoring( - region.identifier, - region.uuid, - region.minor ? region.minor : -1, - region.major ? region.major : -1, - resolve, - reject - ); - }); -} - -/** - * start ranging a region (with optional UUID) - * - * @param {string} regionId specified region to range - * @param {string} [beaconsUUID] optional UUID - * @returns {Promise} promise resolves to void or error - */ -function startRangingBeaconsInRegion(regionId: string, beaconsUUID?: string): Promise { - return new Promise( - (resolve, reject) => { - beaconsAndroid.startRanging(regionId, beaconsUUID, resolve, reject); - } - ); -} - -/** - * stops monittorings for a region - * - * @param {BeaconRegion} region region (see BeaconRegion type) - * @returns {Promise} promise resolves to void or error - */ -function stopMonitoringForRegion(region: BeaconRegion): Promise { - return new Promise( - (resolve, reject) => { - beaconsAndroid.stopMonitoring( - region.identifier, - region.uuid, - region.minor ? region.minor : -1, - region.major ? region.major : -1, - resolve, - reject - ); - } - ); -} - -/** - * Stops the range scan for beacons - * - * @param {string} regionId specified region to stop scan - * @param {string} beaconsUUID optional UUID within the specified region - * @returns {Promise} promise: resolves to void when successful - */ -function stopRangingBeaconsInRegion(regionId: string, beaconsUUID?: string): Promise { - return new Promise( - (resolve, reject) => { - beaconsAndroid.stopRanging(regionId, beaconsUUID, resolve, reject); - } - ); -} - -module.exports = { - setHardwareEqualityEnforced, - detectIBeacons, - detectAltBeacons, - detectEstimotes, - detectEddystoneUID, - detectEddystoneTLM, - detectEddystoneURL, - detectCustomBeaconLayout, - setBackgroundScanPeriod, - setBackgroundBetweenScanPeriod, - setForegroundScanPeriod, - setRssiFilter, - checkTransmissionSupported, - getRangedRegions, - getMonitoredRegions, - startMonitoringForRegion, - startRangingBeaconsInRegion, - stopMonitoringForRegion, - stopRangingBeaconsInRegion, - ARMA_RSSI_FILTER, - RUNNING_AVG_RSSI_FILTER -}; diff --git a/lib/module.ios.js b/lib/module.ios.js deleted file mode 100644 index 8f885510..00000000 --- a/lib/module.ios.js +++ /dev/null @@ -1,7 +0,0 @@ -// @flow - -const RN = require('react-native'); - -const NativeRNiBeacons = RN.NativeModules.RNiBeacon; - -module.exports = NativeRNiBeacons; diff --git a/lib/next/new.module.android.js b/lib/next/new.module.android.js index 612319f4..7d13d879 100644 --- a/lib/next/new.module.android.js +++ b/lib/next/new.module.android.js @@ -17,6 +17,7 @@ import { } from './module.types'; const BeaconsManager: BeaconsManagerANDROID = RN.NativeModules.BeaconsAndroidModule; +const BeaconsEventEmitter = RN.DeviceEventEmitter; const ARMA_RSSI_FILTER = BeaconsManager.ARMA_RSSI_FILTER; const RUNNING_AVG_RSSI_FILTER = BeaconsManager.RUNNING_AVG_RSSI_FILTER; @@ -238,6 +239,8 @@ function stopRangingBeaconsInRegion( } module.exports = { + BeaconsEventEmitter, + setHardwareEqualityEnforced, detectIBeacons, detectAltBeacons, diff --git a/lib/next/new.module.ios.js b/lib/next/new.module.ios.js index 374246ad..3d5ca052 100644 --- a/lib/next/new.module.ios.js +++ b/lib/next/new.module.ios.js @@ -9,6 +9,7 @@ import type { } from './module.types'; const BeaconsManager: BeaconsManagerIOS = RN.NativeModules.RNiBeacon; +const BeaconsEventEmitter = new RN.NativeEventEmitter(BeaconsManager); /** * request always authorization (mandatory when ranging beacons but energy drain) @@ -143,6 +144,8 @@ function stopRangingBeaconsInRegion( } module.exports = { + BeaconsEventEmitter, + requestAlwaysAuthorization, requestWhenInUseAuthorization, getAuthorizationStatus,