ios蓝牙开发学习笔记(二)central角色的实现
本文转载自:http://blog.csdn.net/swibyn/article/details/52096321
Performing Common Central Role Tasks
central角色的实现
central 角色需要完成的几件事情,如搜索,连接,与peripheral交互数据。
peripheral 角色同样需要完成几件事情,如,发布和广播服务,响应读,写,订阅请求
本章中,你将学习如何完成central端的功能。
1,创建central manager 对象
2,发现和连接正在广播的peripheral
3,浏览peripheral的数据
4,发送读和写请求到peripheral设备
5,订阅characteristic的值
下一章你将学习如何开发peripheral角色的功能
Starting Up a Central Manager
创建Central manager对象
myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];'
在这里self设置成central角色的代理。dispath queue设置为nil,意味着central事件将交由main queue处理。
创建central manager时,会触发centralManagerDidUpdateState: 代理方法。你必须实现这个代理。
Discovering Peripheral Devices That Are Advertising
搜索正在发送广播的peripheral
[myCentralManager scanForPeripheralsWithServices:nil options:nil];
注意:如果第一个参数设置成nil,那么centralmanager会返回所有被发现的peripherals,在实际应用中,你应该给他赋值 CBUUID 对象数组。这样只有有广播这些uuid服务的peripheral才会被返回,
一旦发现peripheral,将触发
centralManager:didDiscoverPeripheral:advertisementData:RSSi:
代理方法,如果你想连接这个peripheral,请使用强引用变量引用它,这样系统就不会释放掉它。
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(@"Discovered %@", peripheral.name);
self.discoveredPeripheral = peripheral;
...
如果你想连接多个设备,你可以使用NSArray来管理他们。不管什么情况,一旦你找到所有你想要的设备,你应该停止扫描以便节省电量。
[myCentralManager stopScan];
Connecting to a Peripheral Device After You’ve Discovered It
连接peripheral
[myCentralManager connectPeripheral:peripheral options:nil];
如果连接成功,则会触发centralManager:didConnectPeripheral:代理方法,与之通讯之前,你需要为它设置代理
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(@"Peripheral connected");
peripheral.delegate = self;
...
Discovering the Services of a Peripheral That You’re Connected To
查询peripheral的服务
建立连接之后,就可以查询数据,第一步就是查询有哪些services。因为广播包有大小限制,在广播中可能没有显示全部的服务信息,这里你可以使用discoverServices: 来查询所有的services。
[peripheral discoverServices:nil];
注意:实际开发中,你不应该传值nil,因为这样做会返回所有的services,包括那些你不需要的services,这样做会浪费时间和电量。所以你应该传递你需要的uuids。
查找到所有的服务会触发peripheral:didDiscoverServices:代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
for (CBService *service in peripheral.services) {
NSLog(@"Discovered service %@", service);
...
}
...
Discovering the Characteristics of a Service
查找characteristics
发现service之后,下一步就是查找characteristics
NSLog(@"Discovering characteristics for service %@", interestingService);
[peripheral discoverCharacteristics:nil forService:interestingService];
注意:实际开发中,不要传nil,这样做会返回所有的characteristics,包括那些你不感兴趣的characteristics。这样做即浪费时间又损耗电量。所以你应该传你需要的uuids的值
查找到characteristics之后,会触发peripheral:didDiscoverCharacteristicsForService:error:代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
for (CBCharacteristic *characteristic in service.characteristics) {
NSLog(@"Discovered characteristic %@", characteristic);
...
}
...
Retrieving the Value of a Characteristic
获取数据
一个characteristic只包含一种信息数据。比如恒温service下的温度characteristic只包含当前温度值,你可以通过读取或订阅来获得这个值。
Reading the Value of a Characteristic
读取characteristic的数据
NSLog(@"Reading value for characteristic %@", interestingCharacteristic);
[peripheral readValueForCharacteristic:interestingCharacteristic];
获取到数据后peripheral调用peripheral:didUpdateValueForCharacteristic:error:代理方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSData *data = characteristic.value;
// parse the data as needed
...
注意:并不是所有的characteristic都是可读的,你可以通过 characteristic的 proterties属性是否包含CBCharacteristicPropertyRead 常量来判断是否可读。在读一个不可读的characteristic的数据值,会在代理方法的error参数中体现异常信息
Subscribing to a Characteristic’s Value
订阅characteristic的值
虽然通过readValueForCharacteristic: 可以有效获取静态值,但如果值是动态改变的,则最好使用订阅的方法。当值变化时,自动获得通知。
设置订阅
[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: %@",[error localizedDescription]);
}
注意:并不是所有的characteristics都可以订阅,可以通过检查characteristic的properties属性是否包含CBCharacteristicPropertyNotify 或 CBCharacteristicPropertyIndicate常量来判断是否可订阅
Writing the Value of a Characteristic
写数据
有时也是需要写数据的,比如恒温器,你需要设置目标温度。如果characteristic是可写的,那么你就可以调用writeValue:forCharacteristic:type: 方法来写入数据。如下:
NSLog(@"Writing value for characteristic %@", interestingCharacteristic);
[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristic type:CBCharacteristicWriteWithResponse];
当你写数据时,你可以标明写类型。上例中,写类型是CBCharacteristicWriteWithResponse, 这种情况下,不管有没有写成功,peripheral都会通过代理通知你。你需要实现这个方法以便处理异常情况。
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(@"Error writing characteristic value: %@",[error localizedDescription]);
}
...
如果你设置的写类型是CBCharacteristicWriteWithoutResponse, 那么写操作会以更有效的方式执行,但不保证写成功,并且不会有报告。peripheral不会通知任何回调。
注意:characteristic可能只支持特定的写类型,或不支持写操作。你可以通过检查properties属性是否包含CBCharacteristicPropertyWriteWithoutResponse 或 CBCharacteristicPropertyWrite 来判断。