Created
January 16, 2019 15:39
-
-
Save ger86/08c0eaeb8f6dee4fd3dabdefc0d7baba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // RNiBeacon.m | |
| // RNiBeacon | |
| // | |
| // Created by MacKentoch on 17/02/2017. | |
| // Copyright © 2017 Erwan DATIN. All rights reserved. | |
| // | |
| #import <CoreLocation/CoreLocation.h> | |
| #import <React/RCTBridge.h> | |
| #import <React/RCTConvert.h> | |
| #import <React/RCTEventDispatcher.h> | |
| #import "RNiBeacon.h" | |
| @interface RNiBeacon() <CLLocationManagerDelegate> | |
| @property (strong, nonatomic) CLLocationManager *locationManager; | |
| @property (assign, nonatomic) BOOL dropEmptyRanges; | |
| @end | |
| @implementation RNiBeacon | |
| RCT_EXPORT_MODULE() | |
| #pragma mark Initialization | |
| - (instancetype)init | |
| { | |
| if (self = [super init]) { | |
| self.locationManager = [[CLLocationManager alloc] init]; | |
| self.locationManager.delegate = self; | |
| // Options to allow app killed state running | |
| self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers; | |
| self.locationManager.allowsBackgroundLocationUpdates = true; | |
| self.locationManager.pausesLocationUpdatesAutomatically = NO; | |
| self.dropEmptyRanges = NO; | |
| } | |
| return self; | |
| } | |
| - (NSArray<NSString *> *)supportedEvents | |
| { | |
| return @[ | |
| @"authorizationStatusDidChange", | |
| @"beaconsDidRange", | |
| @"regionDidEnter", | |
| @"regionDidExit", | |
| @"didDetermineState" | |
| ]; | |
| } | |
| #pragma mark | |
| -(CLBeaconRegion *) createBeaconRegion: (NSString *) identifier | |
| uuid: (NSString *) uuid | |
| major: (NSInteger) major | |
| minor:(NSInteger) minor | |
| { | |
| NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:uuid]; | |
| unsigned short mj = (unsigned short) major; | |
| unsigned short mi = (unsigned short) minor; | |
| CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID major:mj | |
| minor:mi | |
| identifier:identifier]; | |
| beaconRegion.notifyOnEntry = YES; | |
| beaconRegion.notifyOnExit = YES; | |
| beaconRegion.notifyEntryStateOnDisplay = YES; | |
| return beaconRegion; | |
| } | |
| -(CLBeaconRegion *) createBeaconRegion: (NSString *) identifier | |
| uuid: (NSString *) uuid | |
| major: (NSInteger) major | |
| { | |
| NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:uuid]; | |
| unsigned short mj = (unsigned short) major; | |
| CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID | |
| major:mj | |
| identifier:identifier]; | |
| beaconRegion.notifyOnEntry = YES; | |
| beaconRegion.notifyOnExit = YES; | |
| beaconRegion.notifyEntryStateOnDisplay = YES; | |
| return beaconRegion; | |
| } | |
| -(CLBeaconRegion *) createBeaconRegion: (NSString *) identifier | |
| uuid: (NSString *) uuid | |
| { | |
| NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:uuid]; | |
| CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID | |
| identifier:identifier]; | |
| beaconRegion.notifyOnEntry = YES; | |
| beaconRegion.notifyOnExit = YES; | |
| beaconRegion.notifyEntryStateOnDisplay = YES; | |
| return beaconRegion; | |
| } | |
| -(CLBeaconRegion *) convertDictToBeaconRegion: (NSDictionary *) dict | |
| { | |
| if (dict[@"minor"] == nil) { | |
| if (dict[@"major"] == nil) { | |
| return [self createBeaconRegion:[RCTConvert NSString:dict[@"identifier"]] | |
| uuid:[RCTConvert NSString:dict[@"uuid"]]]; | |
| } else { | |
| return [self createBeaconRegion:[RCTConvert NSString:dict[@"identifier"]] | |
| uuid:[RCTConvert NSString:dict[@"uuid"]] | |
| major:[RCTConvert NSInteger:dict[@"major"]]]; | |
| } | |
| } else { | |
| return [self createBeaconRegion:[RCTConvert NSString:dict[@"identifier"]] | |
| uuid:[RCTConvert NSString:dict[@"uuid"]] | |
| major:[RCTConvert NSInteger:dict[@"major"]] | |
| minor:[RCTConvert NSInteger:dict[@"minor"]]]; | |
| } | |
| } | |
| -(NSDictionary *) convertBeaconRegionToDict: (CLBeaconRegion *) region | |
| { | |
| if (region.minor == nil) { | |
| if (region.major == nil) { | |
| return @{ | |
| @"identifier": region.identifier, | |
| @"uuid": [region.proximityUUID UUIDString], | |
| }; | |
| } else { | |
| return @{ | |
| @"identifier": region.identifier, | |
| @"uuid": [region.proximityUUID UUIDString], | |
| @"major": region.major | |
| }; | |
| } | |
| } else { | |
| return @{ | |
| @"identifier": region.identifier, | |
| @"uuid": [region.proximityUUID UUIDString], | |
| @"major": region.major, | |
| @"minor": region.minor | |
| }; | |
| } | |
| } | |
| -(NSString *)stringForProximity:(CLProximity)proximity { | |
| switch (proximity) { | |
| case CLProximityUnknown: return @"unknown"; | |
| case CLProximityFar: return @"far"; | |
| case CLProximityNear: return @"near"; | |
| case CLProximityImmediate: return @"immediate"; | |
| default: return @""; | |
| } | |
| } | |
| RCT_EXPORT_METHOD(requestAlwaysAuthorization) | |
| { | |
| if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { | |
| [self.locationManager requestAlwaysAuthorization]; | |
| } | |
| } | |
| RCT_EXPORT_METHOD(requestWhenInUseAuthorization) | |
| { | |
| if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) { | |
| [self.locationManager requestWhenInUseAuthorization]; | |
| } | |
| } | |
| RCT_EXPORT_METHOD(allowsBackgroundLocationUpdates:(BOOL)allow) | |
| { | |
| self.locationManager.allowsBackgroundLocationUpdates = allow; | |
| } | |
| RCT_EXPORT_METHOD(getAuthorizationStatus:(RCTResponseSenderBlock)callback) | |
| { | |
| callback(@[[self nameForAuthorizationStatus:[CLLocationManager authorizationStatus]]]); | |
| } | |
| RCT_EXPORT_METHOD(getMonitoredRegions:(RCTResponseSenderBlock)callback) | |
| { | |
| NSMutableArray *regionArray = [[NSMutableArray alloc] init]; | |
| for (CLBeaconRegion *region in self.locationManager.monitoredRegions) { | |
| [regionArray addObject: [self convertBeaconRegionToDict: region]]; | |
| } | |
| callback(@[regionArray]); | |
| } | |
| RCT_EXPORT_METHOD(startMonitoringForRegion:(NSDictionary *) dict | |
| startMonitoringResolver:(RCTPromiseResolveBlock)resolve | |
| startMonitoringRejecter:(RCTPromiseRejectBlock)reject) | |
| { | |
| // App killed State Running | |
| [self.locationManager startMonitoringSignificantLocationChanges]; | |
| [self.locationManager startMonitoringForRegion:[self convertDictToBeaconRegion:dict]]; | |
| NSDictionary *lastEvent = [[NSUserDefaults standardUserDefaults] objectForKey:[dict objectForKey:@"uuid"]]; | |
| resolve(lastEvent); | |
| } | |
| RCT_EXPORT_METHOD(startRangingBeaconsInRegion:(NSDictionary *) dict) | |
| { | |
| [self.locationManager startRangingBeaconsInRegion:[self convertDictToBeaconRegion:dict]]; | |
| } | |
| RCT_EXPORT_METHOD(stopMonitoringForRegion:(NSDictionary *) dict) | |
| { | |
| // App killed State Running | |
| [self.locationManager stopMonitoringSignificantLocationChanges]; | |
| [self.locationManager stopMonitoringForRegion:[self convertDictToBeaconRegion:dict]]; | |
| } | |
| RCT_EXPORT_METHOD(stopRangingBeaconsInRegion:(NSDictionary *) dict) | |
| { | |
| [self.locationManager stopRangingBeaconsInRegion:[self convertDictToBeaconRegion:dict]]; | |
| } | |
| RCT_EXPORT_METHOD(startUpdatingLocation) | |
| { | |
| [self.locationManager startUpdatingLocation]; | |
| } | |
| RCT_EXPORT_METHOD(stopUpdatingLocation) | |
| { | |
| [self.locationManager stopUpdatingLocation]; | |
| } | |
| RCT_EXPORT_METHOD(shouldDropEmptyRanges:(BOOL)drop) | |
| { | |
| self.dropEmptyRanges = drop; | |
| } | |
| -(NSString *)nameForAuthorizationStatus:(CLAuthorizationStatus)authorizationStatus | |
| { | |
| switch (authorizationStatus) { | |
| case kCLAuthorizationStatusAuthorizedAlways: | |
| return @"authorizedAlways"; | |
| case kCLAuthorizationStatusAuthorizedWhenInUse: | |
| return @"authorizedWhenInUse"; | |
| case kCLAuthorizationStatusDenied: | |
| return @"denied"; | |
| case kCLAuthorizationStatusNotDetermined: | |
| return @"notDetermined"; | |
| case kCLAuthorizationStatusRestricted: | |
| return @"restricted"; | |
| } | |
| } | |
| // Allow location update in app killed state | |
| -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ | |
| //Do nothing here, but enjoy ranging callbacks in background :-) | |
| } | |
| // Allow location update in app killed state | |
| -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ | |
| //Do nothing here, but enjoy ranging callbacks in background :-) | |
| } | |
| -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status | |
| { | |
| NSString *statusName = [self nameForAuthorizationStatus:status]; | |
| [self sendEventWithName:@"authorizationStatusDidChange" body:statusName]; | |
| } | |
| -(void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error | |
| { | |
| } | |
| -(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error { | |
| } | |
| -(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)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 | |
| { | |
| if (self.dropEmptyRanges && beacons.count == 0) { | |
| return; | |
| } | |
| NSMutableArray *beaconArray = [[NSMutableArray alloc] init]; | |
| for (CLBeacon *beacon in beacons) { | |
| [beaconArray addObject:@{ | |
| @"uuid": [beacon.proximityUUID UUIDString], | |
| @"major": beacon.major, | |
| @"minor": beacon.minor, | |
| @"rssi": [NSNumber numberWithLong:beacon.rssi], | |
| @"proximity": [self stringForProximity: beacon.proximity], | |
| @"accuracy": [NSNumber numberWithDouble: beacon.accuracy], | |
| @"distance": [NSNumber numberWithDouble: beacon.accuracy], | |
| }]; | |
| } | |
| NSDictionary *event = @{ | |
| @"region": @{ | |
| @"identifier": region.identifier, | |
| @"uuid": [region.proximityUUID UUIDString], | |
| }, | |
| @"beacons": beaconArray | |
| }; | |
| [self sendEventWithName:@"beaconsDidRange" body:event]; | |
| } | |
| -(void)locationManager:(CLLocationManager *)manager | |
| didEnterRegion:(CLBeaconRegion *)region { | |
| NSDate *now = [NSDate date]; | |
| NSDictionary *regionDict = [self convertBeaconRegionToDict: region]; | |
| NSDictionary *event = @{ | |
| @"region": regionDict, | |
| @"type": @"didEnter", | |
| @"date": [NSNumber numberWithUnsignedInteger:now.timeIntervalSince1970] | |
| }; | |
| [[NSUserDefaults standardUserDefaults] setObject:event forKey:regionDict[@"uuid"]]; | |
| [[NSUserDefaults standardUserDefaults] synchronize]; | |
| [self sendEventWithName:@"regionDidEnter" body:event]; | |
| } | |
| -(void)locationManager:(CLLocationManager *)manager | |
| didExitRegion:(CLBeaconRegion *)region { | |
| NSDate *now = [NSDate date]; | |
| NSDictionary *regionDict = [self convertBeaconRegionToDict: region]; | |
| NSDictionary *event = @{ | |
| @"region": regionDict, | |
| @"type": @"didExit", | |
| @"date": [NSNumber numberWithUnsignedInteger:now.timeIntervalSince1970] | |
| }; | |
| [[NSUserDefaults standardUserDefaults] setObject:event forKey:regionDict[@"uuid"]]; | |
| [[NSUserDefaults standardUserDefaults] synchronize]; | |
| [self sendEventWithName:@"regionDidExit" body:event]; | |
| } | |
| + (BOOL)requiresMainQueueSetup | |
| { | |
| return YES; | |
| } | |
| - (NSNumber*)calculateDistance:(NSNumber*)txPower rssi:(NSNumber*) rssi { | |
| if ([rssi floatValue] >= 0){ | |
| return [NSNumber numberWithInt:-1]; | |
| } | |
| float ratio = [rssi floatValue] / ([txPower floatValue] - 41); | |
| if (ratio < 1.0) { | |
| return [NSNumber numberWithFloat:pow(ratio, 10)]; | |
| } | |
| float distance = (0.89976) * pow(ratio, 7.7095) + 0.111; | |
| return [NSNumber numberWithFloat:distance]; | |
| } | |
| @end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment