我想了解CLBeacons的工作原理 . 我之前曾使用过CBPeripherals,它实际上是BLE设备的核心蓝牙框架实现 .
我做的是以下步骤:
-
使用CBPeripheralManager来检测我周围的信标,(获取每个信标的个人标识符) .
-
使用要在UITableView上显示的数据
-
在选择Tableview时,我将CBPeripheral对象本身传递给另一个我有CLLocationManager的类 . 在这里,我使用CBPeripheral对象的邻近UUID和该区域中的startToRangeBeacons定义CLBeaconRegion .
没有信标出现 .
出人意料的是,当我使用[NSUUID页头] initWithUUIDString:@ “E2C56DB5-DFFB-48D2-B060-D0F5A71096E0”]作为UUID(这是我从AirLocate项目聚集),多个信标出现 .
根据我读过的文档,邻近UUID是信标的标识符 . 那么为什么当我使用传递的标识符时它不起作用,为什么它在我使用定义的标识符时有效?
代码---- 1.第一个屏幕
#import "TiBViewController.h"
#import "DEASensorTag.h"
#import "TiBScanTableViewCell.h"
#import "TiBLocateViewController.h"
@interface TiBViewController ()
@property (nonatomic,strong) NSTimer *timer_check;
@end
@implementation TiBViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
[self performSelector:@selector(initialise) withObject:self afterDelay:2.0];
}
-(void)initialise
{
DEACentralManager *centralManager = [DEACentralManager initSharedServiceWithDelegate:self];
if (centralManager.isScanning == NO)
{
[centralManager startScan];
centralManager.isScanning=YES;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
if(self.timer_check==nil)
{
self.timer_check = [NSTimer timerWithTimeInterval:20
target:self
selector:@selector(timer_function)
userInfo:nil
repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:self.timer_check forMode: NSDefaultRunLoopMode];
}
[self.timer_check fire];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state)
{
case CBCentralManagerStatePoweredOn:
break;
case CBCentralManagerStatePoweredOff:
break;
case CBCentralManagerStateUnsupported:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Device is Supported"
delegate:nil
cancelButtonTitle:@"Dismiss"
otherButtonTitles:nil];
[alert show];
break;
}
case CBCentralManagerStateResetting:
{
break;
}
case CBCentralManagerStateUnauthorized:
break;
case CBCentralManagerStateUnknown:
break;
default:
break;
}
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
DEACentralManager *centralManager = [DEACentralManager sharedService];
YMSCBPeripheral *yp = [centralManager findPeripheral:peripheral];
yp.delegate = self;
[yp readRSSI];
for (TiBScanTableViewCell *cell in [self.peripheralsTableView visibleCells])
{
if (cell.yperipheral == yp)
{
[cell updateDisplay];
break;
}
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
for (TiBScanTableViewCell *cell in [self.peripheralsTableView visibleCells])
{
[cell updateDisplay];
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
DEACentralManager *centralManager = [DEACentralManager sharedService];
YMSCBPeripheral *yp = [centralManager findPeripheral:peripheral];
if (yp.isRenderedInViewCell == NO)
{
yp.isRenderedInViewCell = YES;
[self.peripheralsTableView reloadData];
}
if (centralManager.isScanning)
{
// if(advertisementData!=nil)
// {
// NSLog(@" ad is %@",advertisementData);
// }
for (TiBScanTableViewCell *cell in [self.peripheralsTableView visibleCells])
{
if (cell.yperipheral.cbPeripheral == peripheral)
{
if (peripheral.state == CBPeripheralStateDisconnected)
{
cell.rssiLabel.text = [NSString stringWithFormat:@"%ld dB", (long)[RSSI integerValue]];
cell.distanceLabel.text = [NSString stringWithFormat:@" distance : %0.3fm",[self calculateAccuracyWithRSSI:[RSSI doubleValue]]];
}
else
{
continue;
}
}
}
}
}
- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals {
DEACentralManager *centralManager = [DEACentralManager sharedService];
for (CBPeripheral *peripheral in peripherals)
{
YMSCBPeripheral *yp = [centralManager findPeripheral:peripheral];
if (yp)
{
yp.delegate = self;
}
}
[self.peripheralsTableView reloadData];
}
- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
DEACentralManager *centralManager = [DEACentralManager sharedService];
for (CBPeripheral *peripheral in peripherals)
{
YMSCBPeripheral *yp = [centralManager findPeripheral:peripheral];
if (yp)
{
yp.delegate = self;
}
}
[self.peripheralsTableView reloadData];
}
#pragma mark - CBPeripheralDelegate Methods
- (void)performUpdateRSSI:(NSArray *)args
{
CBPeripheral *peripheral = args[0];
[peripheral readRSSI];
}
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error {
if (error)
{
NSLog(@"ERROR: readRSSI failed, retrying. %@", error.description);
if (peripheral.state == CBPeripheralStateConnected)
{
NSArray *args = @[peripheral];
[self performSelector:@selector(performUpdateRSSI:) withObject:args afterDelay:2.0];
}
return;
}
[self placeRSSI:peripheral];
DEACentralManager *centralManager = [DEACentralManager sharedService];
YMSCBPeripheral *yp = [centralManager findPeripheral:peripheral];
NSArray *args = @[peripheral];
[self performSelector:@selector(performUpdateRSSI:) withObject:args afterDelay:yp.rssiPingPeriod];
}
-(void)placeRSSI:(CBPeripheral *)per
{
for (TiBScanTableViewCell *cell in [self.peripheralsTableView visibleCells])
{
if (cell.yperipheral)
{
if (cell.yperipheral.isConnected)
{
if (cell.yperipheral.cbPeripheral == per)
{
cell.rssiLabel.text = [NSString stringWithFormat:@"%@", per.RSSI];
cell.distanceLabel.text = [NSString stringWithFormat:@" distance : %0.3fm",[self calculateAccuracyWithRSSI:[per.RSSI doubleValue]]];
break;
}
}
}
}
}
#pragma mark UITableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
DEACentralManager *centralManager = [DEACentralManager sharedService];
return centralManager.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"ListCell";
DEACentralManager *centralManager = [DEACentralManager sharedService];
YMSCBPeripheral *yp = [centralManager peripheralAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
TiBScanTableViewCell *pcell = (TiBScanTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[pcell configureWithPeripheral:yp];
yp.isRenderedInViewCell = YES;
cell = pcell;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DEACentralManager *centralManager = [DEACentralManager sharedService];
YMSCBPeripheral *yp = [centralManager peripheralAtIndex:indexPath.row];
TiBLocateViewController *locate = [self.storyboard instantiateViewControllerWithIdentifier:@"Locate"];
locate.cbPeripheral=yp.cbPeripheral;
[self.navigationController pushViewController:locate animated:YES];
}
-(void)timer_function
{
DEACentralManager *centralManager = [DEACentralManager sharedService];
for (TiBScanTableViewCell *cell in [self.peripheralsTableView visibleCells])
{
NSIndexPath *indexPath = [self.peripheralsTableView indexPathForCell:cell];
YMSCBPeripheral *yp = [centralManager peripheralAtIndex:indexPath.row];
[centralManager removePeripheral:yp];
[self.peripheralsTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
-(void)viewWillDisappear:(BOOL)animated
{
[self.timer_check invalidate];
self.timer_check = nil;
[self timer_function];
DEACentralManager *centralManager = [DEACentralManager sharedService];
[centralManager stopScan];
[super viewWillDisappear:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (double)calculateAccuracyWithRSSI:(double)rssi
{
if (rssi == 0) {
return -1.0;
}
double txPower = -70;
double ratio = rssi*1.0/txPower;
if (ratio < 1.0) {
return pow(ratio,10);
}
else {
double accuracy = (0.89976) * pow(ratio,7.7095) + 0.111;
return accuracy;
}
}
@end
- 第二个屏幕
#import“TiBLocateViewController.h”@import CoreLocation;
@interface TiBLocateViewController ()<CLLocationManagerDelegate>
@property (strong,nonatomic) CLLocationManager *locateManager;
@end
@implementation TiBLocateViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.locateManager = [[CLLocationManager alloc]init];
self.locateManager.delegate=self;
self.locateManager.desiredAccuracy = kCLLocationAccuracyBest;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized)
{
NSUUID *per_uuid = self.cbPeripheral.identifier;
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc]
initWithProximityUUID:per_uuid
identifier:[[NSBundle mainBundle] bundleIdentifier]];
beaconRegion.notifyOnExit=YES;
beaconRegion.notifyOnEntry=YES;
beaconRegion.notifyEntryStateOnDisplay=YES;
[manager startMonitoringForRegion:beaconRegion];
[manager startRangingBeaconsInRegion:beaconRegion];
}
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
if ([region isKindOfClass:[CLBeaconRegion class]])
{
[manager startRangingBeaconsInRegion:(CLBeaconRegion *)region];
}
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
if ([region isKindOfClass:[CLBeaconRegion class]])
{
[manager startRangingBeaconsInRegion:(CLBeaconRegion *)region];
}
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
for (CLBeacon *beacon in beacons)
{
NSLog(@" beacon %@",beacon);
}
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@" error is %@",error.localizedDescription);
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
if ([region isKindOfClass:[CLBeaconRegion class]])
{
[manager stopRangingBeaconsInRegion:(CLBeaconRegion *)region];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:YES];
[self.locateManager stopMonitoringSignificantLocationChanges];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
1 回答
虽然iBeacons使用蓝牙低功耗,但它们并未与iOS中的Core-Bluetooth库一起使用 . 它们通过Core Location处理 .
信标区域根据三个参数定义--UUID,主要和次要 .
iBeacon UUID与蓝牙MAC地址不同 - 它更像是“供应商ID” . 给定供应商或所有者的所有信标都将具有相同的UUID - 例如Acme Dept商店将为自己分配一个UUID并将其分配给所有信标,而Big Bank Corp将分配一个不同的信标并将其分配给他们 . 然后,他们可以使用主要和次要来指示不同的位置 . 例如,百货商店可能有主要=商店号码和次要=部门号码(鞋子= 1,食物= 2等等) . 银行专业可能是分支机构,而辅修专业可能是分支机构(1 =出纳员,2 = ATM,3 =后台) .
还有一些“众所周知的”UUID正在使用中 - 例如,你找到了AirLocate . Estimote也有一个默认情况下它们的信标附带 .
如果要扫描信标区域,则必须至少指定UUID . 您还可以选择指定主要和次要 . 当检测到与您正在扫描的信标区域匹配的信标时,您将收到通知(取决于您已激活的模式,输入/退出区域或didRangeBeacon) .
一些信标可以另外实现BLE外围服务和用于设置其参数的特性(UUID,主要,次要,发送级别),但这不是iBeacon规范的一部分,因此不同的供应商将有不同的方法来执行此操作 . 要使用这些设置,您可以使用Core-Bluetooth .
因此,总而言之,如果您只是处理iBeacon方面的事情,那么您不需要对Core-Bluetooth做任何事情 . 您只需要Core-Location .