在这一讲中,我们将学习如何开发Central蓝牙应用,包括:
- 建立Central管理模块CBCentralManager
- 发现和连接正在广播对Peripheral
- 在和Peripheral建立连接后获取数据
- 发送读写Characteristic的请求
- 订阅某个Characteristic,在该值更新后获取新值
建立Central管理模块CBCentralManager
在你准备开始任何蓝牙会话之前,我们需要创建一个CBCentralManager的实例来表示你的Central设备。使用CBCentralManager的初始化方法initWithDelegate:queue:options
CBCentralManager* myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
当你创建完CBCentralManager后,CentralManager会调用centralManagerDidUpdateState:
,这个方法是CBCentralManagerProtocol中提供的方法,你必须在你的应用中实现。
发现正在广播对Peripheral
第一节提到,Peripheral设备通过广播来使其他设备得知自己的存在。通过调用CBCentralManager的scanForPeripheralsWithServices:options:
方法来获取正在广播的Peripheral信息:
[CBCentralManager scanForPeripheralsWithServices:nil options:nil];
关于scanForPeripheralsWithServices参数,需要说明的是,当参数值为nil,该方法会返回所有正在广播的Peripheral。如果你指定某个Service或者一组Service,你可以将表示该Service的UUID(在CoreBluetooth框架中用CBUUID表示)数组传递给该参数,这样CBCentralManager就只会找能够提供这些Service的Peripheral。
在你调用scanForPeripheralsWithServices
后,Central Manager会调用CBCentralManagerDelegate的centralManager:didDiscoverPeripheral:advertisementData:RSSI:
。通过实现该方法,你能够指定你的Central设备在发现Peripheral广播后作出何种反应,例如显示Peripheral的名称:
- (void) centralManager:(CBCentralManager*)central didDiscoverPeripheral:(CBPeripheral*)peripheral advertisementData:(NSDictionary*)advertisementData RSSI:(NSNumber*)RSSI {
NSLog(@"Discovered peripheral: %@", peripheral.name);
}
当你找到自己感兴趣的设备时,你可以选择停止扫描以节约电能:
[myCentralManager stopScan];
NSLog(@"Scanning stopped");
连接发现的Peripheral
既然已经发现了Peripheral,下一步就让我们来与其建立连接:
[myCentralManager connectPeripheral:peripheral options:nil];
假设连接成功,那么Central Manager就会调用didConnectPeripheral方法,而你需要实现该方法:
- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(@"Peripheral connected");
}
在你准备和Peripheral准备交互之前,你需要设置Peripheral的代理以确保其能够获得正确的回调函数。
peripheral.delegate = self;
发现所连Peripheral的Service
一旦连接成功,你可以访问Peripheral上的数据。虽然之前我们得到了一些广播数据,但由于广播的容量限制,那只是所有数据中的一部分。通过调用CBPeripheral的discoverServices函数来获取所有Services数据:
[peripheral discoverServices:nil];
同样地,这里Service可以用UUID数组来指定。
一旦发现需要的Service,Peripheral会调用其Delegate的peripheral:didDiscoverServices
函数,而你需要实现该函数:
- (void)peripheral:(CBPeripheral*)peripheral
didDiscoverServices:(NSError *)error {
for (CBService *service in peripheral.services) {
NSLog(@"Discovered service %@", service);
}
发现Service的Characteristics
当发现Service后,下一步就是探求其中有哪些Characteristic:
NSLog(@"Discovering characteristics for service %@", interestingService);
[peripheral discoverCharacteristics:nil forService:interestingService];
同样地,你也可以指定Characteristic的UUID数组来获取需要的Characteristic。
一旦成功发现指定的Characteristic,Peripheral便会调用Delegate的peripheral:didDiscoverCharacteristicsForService:error:
函数:
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error {
for (CBCharacteristic *characteristic in service.characteristics) {
NSLog(@"Discovered characteristic %@", characteristic);
}
读取Characteristic数据值
Characteristic中包含着Service的单个值,通过CBPeripheral的readValueForCharacteristic我们可以读出其值。
NSLog(@"Reading value for characteristic %@", interestingCharacteristic);
[peripheral readValueForCharacteristic:interestingCharacteristic];
当从Characteristic中去读到值后,CBPeripheral会调用起代理的peripheral:didUpdateValueForCharacteristic:error:
函数:
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
NSData *data = characteristic.value;
// parse the data as needed
}
有的时候Characteristic是不可读的,你可以通过访问CBCharacteristicPropertyRead常量来判断。
订阅Characteristic值
读取Characteristic值在正常情况下并不是最有效的,大多数情况下我们更想知道某个值的最新值,我们可以通过订阅该Characteristic来获取实时更新的通知。
[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];
一旦调用上面的函数,peripheral便会调用其代理的peripheral:didUpdateNotificationStateForCharacteristic:error:
函数。
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
if (error) {
NSLog(@"Error changing notification state: %@",
}
同样并非所有Characteristic都能够被订阅,你需要访问相应的常量来获取订阅配置的信息。
订阅成功以后,你就可以在didUpdateValueForCharacteristic方法中通过readValueForCharacteristic来获取更新的值。
写Characteristic值
向Peripheral中写值可以通过CBPeripheral的writeValue:forCharacteristic:type:
函数来实现。
NSLog(@"Writing value for characteristic %@", interestingCharacteristic);
[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristic
type:CBCharacteristicWriteWithResponse];
type用来指定以何种方式写入。上面代码中的CBCharacterisitcWriteWithResponse表示你的应用会告诉你写入是否成功。在指定为该类型的写入模式下,会调用peripheral代理的peripheral:didWriteValueForCharacteristic:error:
函数:
- (void) peripheral:(CBPeripheral*)peripheral didWriteValueForCharacteristic:(CBCharacteristic*)characteristic error:(NSError*)error
{
if (error) {
NSLog(@"Error writing characteristic value: %@",[error localizedDescription]);
}
}
并不是所有的Characteristic都是可写的,需要访问相应常量来获取配置信息。
好了,写了这么多,我们终于对如何与Peripheral进行信息交互有了一个感性上的认识。所谓实践是检验真理的唯一标准,我们在之后的几节里将重点讲解一个实际的demo。