IOS-CoreBluetooth基础

来源:互联网 发布:华为无法访问移动网络 编辑:程序博客网 时间:2024/05/22 06:49

刚踏入iOS大门的小白,由于在深圳工作,所以与硬件设备打交道是不可避免的,尤其是蓝牙设备,所以将自己学习和实践得到的一些经验在这里分享一下,同时感谢众多博文的写手无私的将经验分享给我这样的新人,写的很简陋,望大家批评指正。

环境信息:
Mac OS X 10.11.4
iOS 9.3.2
Xcode 7.3.1
Bluetooth 4.0

正文:
公司主要做车联网方面的业务,正准备做一款可以与下位机实时通讯的app,所以不得不去了解一下蓝牙方面的知识。
最可靠的信息来源当数官方提供的文档,全面,细致,但我一点没看过,因为看英文就想睡觉,如果你有兴趣可以点下方链接:
官方api

IOS蓝牙介绍
苹果自4s之后支持CoreBluetooth框架,可以以central身份去连接支持ble 蓝牙4.0的设备获取数据,在ios6之后可以以peripheral身份被其他设备连接提供数据。蓝牙4.0以低功耗著称,说白了就是更省电,所以在智能家居、车联网、智能穿戴设备上应用广泛,前景不错,值得日后更深入的研究。
其他相关的理论资料网上很多,我也就不再赘述,但建议还是多看看官方文档或者找一两个介绍全面的博文研究,不然收集一大堆散碎的信息会让你很头大。本文就以我写的一个用来测试公司蓝牙模块数据收发能力的小demo为例介绍一下以iphone为central时一些必要的方法。如学习再有斩获,也会实时更新。

第一步 初始化

_manager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];

第一步我们先初始化CBCentralManager,queue设为nil表示在主线程中执行。
当执行完初始化,会调用@method centralManagerDidUpdateState:方法,他会判断当前设备是否适合成为central。而我们也可以通过这个方法检测设备蓝牙是否可用。

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{    switch (central.state) {        case CBCentralManagerStatePoweredOn:                NSLog(@"蓝牙已打开, 请扫描外设!");            break;        case CBCentralManagerStatePoweredOff:            NSLog(@"蓝牙未打开!");            break;        default:            break;    }}

第二步 搜索当前可用peripheral
我们通过@method scanForPeripheralsWithServices:options:方法扫描可用外设。

-(void)scan{    NSDictionary* Options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];      if(_peripheral != nil){        [_manager cancelPeripheralConnection:_peripheral];    }    [self.manager scanForPeripheralsWithServices:nil options:Options];}

其中Services:nil表示扫描附近所有可用外设,你也可以传一个uuid的数组或者单个的uuid,但我尝试过设置蓝牙模块的uuid并不能扫描到,不知道为什么。需要说明的一点是,CoreBluetooth搜索到服务和特征的uuid都是经过优化的16位,不是128位,但并不影响使用。options 这个参数可以设为nil,表示多次扫描到同一个外设视为同一个事件,在某些特定场景下可以做如上面代码的处理,比如得到实时rssi,但会耗费设备的电量和性能。
一旦扫描成果,会调用@method centralManager:didDiscoverPeripheral:advertisementData:RSSI:方法。

- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{          [_peripherals addObject:peripheral];    [self.manager stopScan];}

我们可以将扫描到的外设存在一个数组里,这里有个坑,就是当你想连接外设之前,一定要[self.manager stopScan],否则很有可能点半天没有反应,还以为自己代码有问题。当然,在开始搜索的时候我们也可以设置一个扫描超时的处理。

double delay = 15;dispatch_time_t Time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay* NSEC_PER_SEC));dispatch_after(Time, dispatch_get_main_queue(), ^(void){        [self.manager stopScan];        NSLog(@"扫描超时");    });

第三步 连接 peripheral
当我们需要连接外设时调用@method connectPeripheral:options:方法。

[self.manager connectPeripheral:_peripheral options:nil];

连接成功后会回调

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{    NSLog(@"Peripheral has connect");    [_peripheral setDelegate:self];}**注意**:你需要给搜到的这个Peripheral设置代理,这样才能收到<CBPeripheralDelegate>协议的其它回调。

连接失败后会回调

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{    NSLog(@"periheral has fail  error : %@", error);}

而当连接中断时会调用

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{    NSLog(@"periheral has disconnect error : %@", error");}

第四步 搜索 peripheral 的 service
现在已经成功搜索到我们想要的外设了,下一步就是看他给我们提供了哪些service。调用@method peripheral:didDiscoverServices:方法。

[_peripheral discoverServices:nil];

成功后回调@method peripheral:didDiscoverServices:方法。

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{    for (CBService *service in peripheral.services)    {        if ([service.UUID isEqual:[CBUUID UUIDWithString:@"xxxx"]]){            NSLog(@"Service found with UUID: %@", service.UUID);               }    }}

此处我的代码其实有些多余,当你明确知道自己需要的service时(不知道具体service的uuid可以下载个lightblue就啥都知道了),可以在[_peripheral discoverServices:nil]这一步直接搜索,高效且省电。

第五步 搜索 service 的 characteristic
既然知道了service,那就该搜索他的characteristic了,调用@method discoverCharacteristics:forService:方法。

[peripheral discoverCharacteristics:nil forService:service];

同理,如果你明确知道需要哪个characteristic,直接在上面设置就好。
成功找到所需characteristic后会回调@method peripheral:didDiscoverCharacteristicsForService:error:方法。

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{       for (CBCharacteristic *characteristic in service.characteristics)    {        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"xxxxx"]]) {         NSLog(@"characteristic found with UUID: %@", characteristic.UUID);               }    }}

第六步 读取 订阅characteristic数据
当你想读取characteristic数据时可以调用@method readValueForCharacteristic:方法。

[peripheral readValueForCharacteristic:characteristic];

之后会回调@method peripheral:didUpdateValueForCharacteristic:error:方法。

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{    NSLog(@"读取到的数据:%@",characteristic.value);}

但 @method readValueForCharacteristic:并不能实时获取数据,需要我们多次的调用,而实际情景往往需要实时获取数据,这时就需要订阅characteristic。调用@method setNotifyValue:forCharacteristic:方法。

[_peripheral setNotifyValue:YES forCharacteristic:characteristic];

将第一个参数设为yes。订阅成功会回调@method peripheral:didUpdateNotificationStateForCharacteristic:error:方法。

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{}

需要注意的是订阅得到数据还是通过@method peripheral:didUpdateValueForCharacteristic:error:方法回传。

第七步 向 characteristic 写数据
当我们需要向蓝牙模块中写数据时,调用@method writeValue:forCharacteristic:type:方法。

[self.peripheral writeValue:value forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];

type的参数表示当写入成功需要回调。回调的方法是@method peripheral:didWriteValueForCharacteristic:error:。

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{    if (error) {        NSLog(@"write characteristic value Error: %@", [error localizedDescription]);    }}

OK,以上便是以iphone为central时的一些必要方法,按着一步一步来就可以实现一些基本的数据读写操作了,对CoreBluetooth框架也会有一定的了解。第一次写博客,有不足之处还望大家谅解并反馈给我,之后还会有一些补充就写在下一篇博客里吧~

4 0