| // |
| // NTViewController.m |
| // HiBeacons |
| // |
| // Created by Nick Toumpelis on 2013-10-06. |
| // Copyright (c) 2013 Nick Toumpelis. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| // |
| |
| #import "NTViewController.h" |
| |
| static NSString * const kUUID = @"00000000-0000-0000-0000-000000000000"; |
| static NSString * const kIdentifier = @"SomeIdentifier"; |
| static NSString * const kCellIdentifier = @"BeaconCell"; |
| |
| @interface NTViewController () |
| |
| @property (nonatomic, strong) CLLocationManager *locationManager; |
| @property (nonatomic, strong) CLBeaconRegion *beaconRegion; |
| @property (nonatomic, strong) CBPeripheralManager *peripheralManager; |
| @property (nonatomic, strong) NSArray *detectedBeacons; |
| |
| @end |
| |
| @implementation NTViewController |
| |
| - (void)viewDidLoad |
| { |
| [super viewDidLoad]; |
| |
| [self.advertisingSwitch addTarget:self |
| action:@selector(changeAdvertisingState:) |
| forControlEvents:UIControlEventValueChanged]; |
| [self.rangingSwitch addTarget:self |
| action:@selector(changeRangingState:) |
| forControlEvents:UIControlEventValueChanged]; |
| } |
| |
| #pragma mark - Beacon ranging |
| - (void)createBeaconRegion |
| { |
| if (self.beaconRegion) |
| return; |
| |
| NSUUID *proximityUUID = [[NSUUID alloc] initWithUUIDString:kUUID]; |
| self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:proximityUUID identifier:kIdentifier]; |
| } |
| |
| - (void)turnOnRanging |
| { |
| NSLog(@"Turning on ranging..."); |
| |
| if (![CLLocationManager isRangingAvailable]) { |
| NSLog(@"Couldn't turn on ranging: Ranging is not available."); |
| self.rangingSwitch.on = NO; |
| return; |
| } |
| |
| if (self.locationManager.rangedRegions.count > 0) { |
| NSLog(@"Didn't turn on ranging: Ranging already on."); |
| return; |
| } |
| |
| [self createBeaconRegion]; |
| [self.locationManager startRangingBeaconsInRegion:self.beaconRegion]; |
| |
| NSLog(@"Ranging turned on for region: %@.", self.beaconRegion); |
| } |
| |
| - (void)changeRangingState:sender |
| { |
| UISwitch *theSwitch = (UISwitch *)sender; |
| if (theSwitch.on) { |
| [self startRangingForBeacons]; |
| } else { |
| [self stopRangingForBeacons]; |
| } |
| } |
| |
| - (void)startRangingForBeacons |
| { |
| self.locationManager = [[CLLocationManager alloc] init]; |
| self.locationManager.delegate = self; |
| |
| [self turnOnRanging]; |
| } |
| |
| - (void)stopRangingForBeacons |
| { |
| if (self.locationManager.rangedRegions.count == 0) { |
| NSLog(@"Didn't turn off ranging: Ranging already off."); |
| return; |
| } |
| |
| [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion]; |
| |
| self.detectedBeacons = nil; |
| [self.beaconTableView reloadData]; |
| |
| NSLog(@"Turned off ranging."); |
| } |
| |
| #pragma mark - Beacon ranging delegate methods |
| - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status |
| { |
| if (![CLLocationManager locationServicesEnabled]) { |
| NSLog(@"Couldn't turn on ranging: Location services are not enabled."); |
| self.rangingSwitch.on = NO; |
| return; |
| } |
| |
| if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) { |
| NSLog(@"Couldn't turn on ranging: Location services not authorised."); |
| self.rangingSwitch.on = NO; |
| return; |
| } |
| |
| self.rangingSwitch.on = YES; |
| } |
| |
| - (void)locationManager:(CLLocationManager *)manager |
| didRangeBeacons:(NSArray *)beacons |
| inRegion:(CLBeaconRegion *)region { |
| if ([beacons count] == 0) { |
| NSLog(@"No beacons found nearby."); |
| } else { |
| NSLog(@"Found %lu %@.", (unsigned long)[beacons count], [beacons count] > 1 ? @"beacons" : @"beacon"); |
| } |
| |
| self.detectedBeacons = beacons; |
| [self.beaconTableView reloadData]; |
| } |
| |
| #pragma mark - Beacon advertising |
| - (void)turnOnAdvertising |
| { |
| if (self.peripheralManager.state != CBPeripheralManagerStatePoweredOn) { |
| NSLog(@"Peripheral manager is off."); |
| self.advertisingSwitch.on = NO; |
| return; |
| } |
| |
| time_t t; |
| srand((unsigned) time(&t)); |
| CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:self.beaconRegion.proximityUUID |
| major:rand() |
| minor:rand() |
| identifier:self.beaconRegion.identifier]; |
| NSDictionary *beaconPeripheralData = [region peripheralDataWithMeasuredPower:nil]; |
| [self.peripheralManager startAdvertising:beaconPeripheralData]; |
| |
| NSLog(@"Turning on advertising for region: %@.", region); |
| } |
| |
| - (void)changeAdvertisingState:sender |
| { |
| UISwitch *theSwitch = (UISwitch *)sender; |
| if (theSwitch.on) { |
| [self startAdvertisingBeacon]; |
| } else { |
| [self stopAdvertisingBeacon]; |
| } |
| } |
| |
| - (void)startAdvertisingBeacon |
| { |
| NSLog(@"Turning on advertising..."); |
| |
| [self createBeaconRegion]; |
| |
| if (!self.peripheralManager) |
| self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil]; |
| |
| [self turnOnAdvertising]; |
| } |
| |
| - (void)stopAdvertisingBeacon |
| { |
| [self.peripheralManager stopAdvertising]; |
| |
| NSLog(@"Turned off advertising."); |
| } |
| |
| #pragma mark - Beacon advertising delegate methods |
| - (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheralManager error:(NSError *)error |
| { |
| if (error) { |
| NSLog(@"Couldn't turn on advertising: %@", error); |
| self.advertisingSwitch.on = NO; |
| return; |
| } |
| |
| if (peripheralManager.isAdvertising) { |
| NSLog(@"Turned on advertising."); |
| self.advertisingSwitch.on = YES; |
| } |
| } |
| |
| - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheralManager |
| { |
| if (peripheralManager.state != CBPeripheralManagerStatePoweredOn) { |
| NSLog(@"Peripheral manager is off."); |
| self.advertisingSwitch.on = NO; |
| return; |
| } |
| |
| NSLog(@"Peripheral manager is on."); |
| [self turnOnAdvertising]; |
| } |
| |
| #pragma mark - Table view functionality |
| - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath |
| { |
| CLBeacon *beacon = self.detectedBeacons[indexPath.row]; |
| |
| UITableViewCell *defaultCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle |
| reuseIdentifier:kCellIdentifier]; |
| |
| defaultCell.textLabel.text = beacon.proximityUUID.UUIDString; |
| |
| NSString *proximityString; |
| switch (beacon.proximity) { |
| case CLProximityNear: |
| proximityString = @"Near"; |
| break; |
| case CLProximityImmediate: |
| proximityString = @"Immediate"; |
| break; |
| case CLProximityFar: |
| proximityString = @"Far"; |
| break; |
| case CLProximityUnknown: |
| default: |
| proximityString = @"Unknown"; |
| break; |
| } |
| defaultCell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@ • %@ • %f • %li", |
| beacon.major.stringValue, beacon.minor.stringValue, proximityString, beacon.accuracy, (long)beacon.rssi]; |
| defaultCell.detailTextLabel.textColor = [UIColor grayColor]; |
| |
| return defaultCell; |
| } |
| |
| - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView |
| { |
| return 1; |
| } |
| |
| - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section |
| { |
| return self.detectedBeacons.count; |
| } |
| |
| - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section |
| { |
| return @"Detected beacons"; |
| } |
| |
| @end |