这一节讲讲外接设备(Peripheral)
,主要是关于CBPeripheralManager
这个类的使用。
0x00 - Starting Up a Peripheral Manager
首先,初始化一个CBPeripheralManager
实例。
1 | myPeripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil]; |
同样的,这里的queue参数设置为nil
表示默认使用主队列。
但你创建完一个 myPeripheralManager 实例的时候,peripheral manager 就会调用它的代理函数peripheralManagerDidUpdateState:
,这边必须实现该函数以确保本地外设支持该蓝牙。
0x01 - Setting up Your Services and Characteristics
Core Bluetooth这一节说过,Peripheral
是由CBService
,CBCharacteristic
组成的,所以我们这边得先创建CBService和CBCharacteristic。
services 和 characteristics 都是由128-bit的UUIDs唯一指定的。例如0000180D-0000-1000-8000-00805F9B34FB
,在开发的过程中CBUUID
提供了一个UUIDWithString
方法,可以使用简短的字符串生成128-bit的UUIDs。
1 | CBUUID *heartRateServiceUUID = [CBUUID UUIDWithString: @"180D"]; |
对于一些没有预设UUIDs的services和Characteristics,你也可以通过命令行uuidgen
生成,然后用这个UUID实例化一个CBUUID
1 | $ uuidgen |
1 | CBUUID *myCustomServiceUUID = [CBUUID UUIDWithString:@"71DA3FD1-7E10-41C1-B16F-4430B506CDE7"]; |
然后,通过 UUID 创建 services 和 characteristics
1 | myService = [[CBMutableService alloc] initWithType:myServiceUUID primary:YES]; |
1 | myCharacteristic = |
接着把characteristics设置给services
1 | myService.characteristics = @[myCharacteristic]; |
0x02 - Publishing Your Services and Characteristics
最后add到peripheral上
1 | [myPeripheralManager addService:myService]; |
当你把service加进来的时候,peripheral 就相当于发布了服务了,这时候会调用delegate的peripheralManager:didAddService:error:
方法,如果发布不成功的话在这里就可以获取到相关的错误原因了。
1 | - (void)peripheralManager:(CBPeripheralManager *)peripheral |
Note: 一旦你发布了服务的时候,services就会被cache起来并且不可再修改!
0x03 - Advertising Your Services
当你发布了服务的时候接下来就需要向Central进行广播了,开始广播可以调用startAdvertising:
这个方法
1 | [myPeripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : |
这里的UUIDsKey指定你要对外广播的servers。目前,这里只提供了2种key可以填写,CBAdvertisementDataLocalNameKey
和 CBAdvertisementDataServiceUUIDsKey
。
当开始对外广播的时候,peripheral 就会调用delegate的peripheralManagerDidStartAdvertising:error:
这个方法,一旦广播出错便可以在这里捕获到。
1 | - (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral |
开启对外广播的时候,周边的centrals就可以发现并和你建立连接
0x04 - Responding to Read and Write Request form a Central
建立起连接之后,
Read
1 | - (void)peripheralManager:(CBPeripheralManager *)peripheral |
接收到请求的第一步便是验证请求的characteristic UUID 是否在外设的数据库里面。
检查通过以后再对请求读取的数据字段做越界检查。
1 | if (request.offset > myCharacteristic.value.length) { |
假设都验证通过的情况下,这直接给请求的request赋值
1 | request.value = [myCharacteristic.value |
赋值成功后再响应请求是否成功,同时把请求的request传递回去
1 | [myPeripheralManager respondToRequest:request withResult:CBATTErrorSuccess]; |
Note: peripheralManager:didReceiveReadRequest:
和respondToRequest:withResult:
是成对出现的。
在接收的request请求的时候,如果本地数据库里面找不到 characteristic 的 UUID 的话需要调用respondToRequest:withResult:
响应请求,告诉请求失败,失败原因可以查看CBATTError Constants这里列举的错误选项。
Write
处理写请求也很容易,当central发起写请求的时候,peripheral manager 会调用peripheralManager:didReceiveWriteRequests:
这个方法响应写请求,之后再把 request里面的value赋给characteristic就好了。当然,同样要检查UUID和越界的情况。
1 | myCharacteristic.value = request.value; |
最后返回响应写请求的结果
1 | [myPeripheralManager respondToRequest:[requests objectAtIndex:0] |
Note: 同样的,peripheralManager:didReceiveWriteRequests:
和respondToRequest:withResult:
是成对出现的。
0x05 - Sending Updated Characteristic Values to Subscribed Centrals
通常,已经连接了的centrals会订阅一个或者多个characteristic的值,当有订阅的时候会调用这个回调函数
1 | - (void)peripheralManager:(CBPeripheralManager *)peripheral |
之后通过调用updateValue:forCharacteristic:onSubscribedCentrals:
这个方法向订阅者通知值的更新
1 | NSData *updatedValue = // fetch the characteristic's new value |
这里的最后一个参数置为nil
表示有链接到或者订阅的central就可以收到消息,其他的则被忽略。
另外,更新完成之后想要知道消息是否已经正确发送到订阅者那里了,可以通过updateValue:forCharacteristic:onSubscribedCentrals:
来确定,如果传送队列没有空间进行发送消息了,则会返回NO,此时可以调用peripheralManagerIsReadyToUpdateSubscribers:
这个方法做延时发送,当队列有空余空间的时候则会继续开始发送
拓展链接: