在 iOS 中,蓝牙是基于 4.0 标准的,设备间低功耗通信。
其中 Peripheral 外设相当于 Socket 编程中的 Server 服务端,Central 中心相当于 Client 客户端。
本地中心 -> 远程外设
本地外设 -> 远程中心
使用流程:
建立中心角色 —> 扫描外设(discover)—> 发现外设后连接外(connect) —> 扫描外设中的服务和特征(discover) —> 与外设做数据交互(explore and interact) —> 断开连接(disconnect)。
1. 建立中心角色
上面的 delegate 为 CBCentralManagerDelegate,后续蓝牙相关的回调都会在此。
queue 代表蓝牙在哪个队列里面操作,如果传入 nil 默认为主队列,值得注意的是后续的回调也是在传入的队列中调用的,所以如果传入的是非主线程的队列,在 delegate 中需要操作 UI 时需要手动切换到主线程。
CBCentralManager 对象创建后会回调到 centralManagerDidUpdateState 方法来检测蓝牙可用状态,这时我们可以提醒用户设备是否支持蓝牙,是否打开了蓝牙。
2. 扫描外设
如果 serviceUUIDS 为 nil 则会扫描周围所有的设外设,反之只会扫描 UUID 匹配的外设。
CBCentralManagerScanOptionAllowDuplicatesKey 默认为 false,此次扫描中发现过设备则跳过不回调,我们这里传入 true,因为下面做外设掉线的处理时需要用到。
传入的 serviceUUIDS 数组元素为 CBUUID 类型,千万不要传入 String,后面的操作也是如此,不然会碰到很多奇葩问题。
发现外设后会回调到 centralManager(central:didDiscoverPeripheral:advertisementData:RSSI:)其中,perpheral 则代表着外设,我们需要保存起来,后续的对外设的操作都是基于 perpheral对象的。
3. 连接外设
传入上面保存的外设对象,如果连接失败后会回调到centralManager(central:didFailToConnectPeripheral:,error:),连接成功后会回调到 centralManager(central:didConnectPeripheral:),这个时候我们只是连接上外设而已,还需要发现外设中的服务与特征。
4. 发现服务与特征
5. 发送数据
6. 读取数据
7. 断开连接
在蓝牙交互的二种角色中,通常 APP 端扮演中央 Central 的角色,设备扮演外设 Peripheral 的角色创建 CBCentralManager 对象时传入的 queue 决定了后续 CBCentralManagerDelegate、CBPeripheralDelegate 等回调的所在线程一个外设设备可包含一个或多个服务,一个服务可包含一个或多个特征,读写操作最终是针对特征。
蓝牙的缓冲大小只有 20bytes,在发送数据时最多只能发送 20bytes,所以得分多次发送,数据的一体性可以用 EOM 标识符表标识。