低功耗蓝牙ibeacon的初级应用
1、直接CoreBluetooth API这是针对蓝牙的API,并不特指低功耗蓝牙,直接上代码:
#import <CoreBluetooth/CoreBluetooth.h>
//<CBCentralManagerDelegate,CBPeripheralDelegate>这两协议是需要遵守的,前一个是扫描相关的代理,后一个是连接后相关的代理
//central是执行扫描的一个执行者
@property(strong,nonatomic)CBCentralManager *central;
-(void)viewdidLoade{
//初始化并设置代理和运行线程
self.central = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
#pragma -mark -CentralManagerDelegate
//在central初始化后,会首先进入这个代理,CBCentralManagerStatePoweredOn状态证明蓝牙功能是正常的,然后scanForPeripheralsWithServices调用,开始搜索附近蓝牙设备,@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}这个option是让扫描可以重复扫同一个设备。
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
if(central.state == CBCentralManagerStatePoweredOn){
[self.central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
}
}
//没扫描到一个设备一次都会调用此代理,返回相关信息,RSSI:信号,advertisementData:广播信息 peripheral:蓝牙对象
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
//code 进行数据相关操作
}
//如果有连接蓝牙设备的需要,通过此方法连接
[self.central connectPeripheral:peripheral options:options];
//连接成功进入的代理,在这里为peripheral设置代理,并调用discover方法查询服务
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
[self.delegata connectState:YES];
peripheral.delegate = self;
[peripheral discoverServices:nil];
}
//连接失败进入的代理
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
[self.delegata connectState:NO];
}
//在discover方法调用后,此代理方法运行,会取得iBeacon服务uuid标识,选取目标service,调用discoverCharacteristics,去获得该服务内的所有特征符。
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
// for (CBService* service in peripheral.services){
// NSLog(@"%@", service.UUID.UUIDString);
// if ([service.UUID.UUIDString isEqualToString:@"FFF0"]) {
// [peripheral discoverCharacteristics:nil forService:service];
// }
// }
NSLog(@"%@",peripheral.services);
[peripheral discoverCharacteristics:nil forService:[peripheral.services firstObject]];
}
//discoverCharacteristics后此代理调用,可取得目标服务的所有状态符信息
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
for (CBCharacteristic *charact in service.characteristics) {
NSLog(@"%@",charact.UUID.UUIDString);
}
}
以上则是该框架下蓝牙的使用,当然只是一部分,peripgeral的代理方法还有很多。接下来看第二种简单使用
2、CoreLocation框架也有蓝牙部分,当然这是在beacon出现之后才有的,由于beacon多被用于位置信息方面,所有将这部分API放入了CoreLocation中
//调用框架,遵循代理,两个属性
#import <CoreLocation/CoreLocation.h>
<CLLocationManagerDelegate>
@property(strong,nonatomic)CLBeaconRegion *region;
@property(strong,nonatomic)CLLocationManager *manager;
-(void)start{
//这个扫描方式并不是扫描所有的蓝牙设备,而是有针对性的,region则是扫描的一个标准,uuidstr,对于每个ibeacon 都有uuid,这个扫描方式则是扫描具有相同uuid的设备,
self.manager = [[CLLocationManager alloc] init];
self.manager.delegate = self;
self.region = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:uuidstr] identifier:identifier];
//app扫描权限的询问
[self.manager requestAlwaysAuthorization];
//这个权限访问被允许后,才可以进入下面的操作
}
#programe delegate
//允许权限后,才能进入此方法,开启Monitoring模式,进入或者退出目标iBeacon的范围,
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
if (status == kCLAuthorizationStatusAuthorizedAlways) {
self.region.notifyOnEntry=YES;
self.region.notifyOnExit=YES;
self.region.notifyEntryStateOnDisplay=YES;
//能够进入这里才进行扫描操作
[self.manager startMonitoringForRegion:self.region];
}
}
//开启Monitoring模式,进入这个代理,locationmanager发送请求信息
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{
NSLog(@"request");
[self.manager requestStateForRegion:self.region];
}
//请求之后调用此代理,如果已经在目标iBeacon范围内,择开启ranging模式
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
NSLog(@"determ");
if (state == CLRegionStateInside)
{
//Start Ranging
[self.manager startRangingBeaconsInRegion:self.region];
}
//进入iBeacon区域执行的代理,在此开启ranging模式
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(@"Entered region");
[self.manager startRangingBeaconsInRegion:self.region];
}
//退出iBeacon区域执行的代理,停止ranging模式
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(@"Exited region");
[self.manager stopRangingBeaconsInRegion:self.region];
}
//开启ranging模式后,不断刷新执行的代理,返回beacon的实时信息(信号,主副值,距离等)
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
//扫描到beacon信息后后进入这里,beacons是此次符合要求的所有beacon设备,region当然是我们的中心标准设备。beacon是个CLBeacon的实例对象,其属性proximityUUID是uuid,major是主值,minor副值,用于表示每一个beacon设备,accuracy距离信息,rss信号强度,总之,所需要的信息,这里面基本都有了。
}
总结,两种模式都可以获得蓝牙信息,前者无目标,针对所有设备,后者目标性唯一,有针对性,一般只用于beacon设备,再者,前者扫描速度很快,而后者比起前面则会慢上许多了,本人感觉,后面的扫描速度大约在1s一次。。
3、此外,iOS后台运行限制比较多,app退出后台时可以执行部分功能,但是如果超过10分钟保持后台状态,任何行为都会被终止。beacon设备是允许在后台进行扫描的,当然效率也会降低,并且只针对明确的beacon设备,不能后才检测未知设备。
首先,蓝牙的后台功能是需要plist文件的相关设置的,![plist.png](https://img-blog.csdn.net/20160226182210005)
这两个是后台运行的前提,然后,iBeacon或者其他基站的广播数据包种必须有这个键值对 kCBAdvDataServiceUUIDs = ~~~ centermanager后台扫描必须执行 serviceuuid才能扫描到基站,并且频率不可控,而且比前台要低很多,
//第一个参数这是扫描指定的iBeacon,为数组,可设置多个,此类基站广播数据包中都会有kCBAdvDataServiceUUIDs== FFF0这个键,
[self.central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FFF0"]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
这个的扫描速度更慢……