其他
用 Core Bluetooth 实现 BLE 中心/外设…
在 iOS/macOS 上用 Core Bluetooth 扫描、连接 BLE 设备并读写/订阅 GATT 特征,或本机作为外设广播服务时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 47/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 51/100 ×0.15
适用场景
用 Core Bluetooth 实现 通用
解决思路
- 在 Info.plist 中添加 NSBluetoothAlwaysUsageDescription;如需后台扫描/连接加 UIBackgroundModes 的 bluetooth-central,如需后台广播加 bluetooth-peripheral。
- Core Bluetooth 没有显式权限请求 API:添加用途描述后,在应用准备好访问蓝牙时创建 manager,然后检查 manager.authorization 和 manager.state;把 .denied 和 .restricted 视为终态直到用户改设置;等待 .poweredOn 后再扫描、连接、广播或发布服务。
- 创建 CBCentralManager 时设置 delegate,并在 centralManagerDidUpdateState 中确认 state == .poweredOn 后再开始扫描。
- 调用 scanForPeripherals(withServices:options:) 时传入具体服务 UUID 以省电;生产环境不要传 nil(nil 会扫描所有外设);可用 CBCentralManagerScanOptionAllowDuplicatesKey 控制重复回调。
- 在 didDiscover peripheral 回调中按 RSSI 过滤弱信号(如 RSSI.intValue > -70),用强引用保存 discoveredPeripheral(否则会被释放),然后 stopScan() 并 connect(peripheral, options: nil)。
- 在 didConnect 回调中设置 peripheral.delegate = self,再调用 discoverServices([...]);在 didDisconnectPeripheral 中检查 isReconnecting,若系统正在自动重连则直接返回,否则处理断开并可选重连。
- 实现 CBPeripheralDelegate:在 didDiscoverServices 中对每个 service 调用 discoverCharacteristics(nil, for: service);在 didDiscoverCharacteristicsFor 中遍历 characteristics,对含 .notify 属性的调用 setNotifyValue(true, for:),对含 .read 属性的调用 readValue(for:)。
- 在 didUpdateValueFor 回调中读取 characteristic.value,按 characteristic.uuid 分支解析数据(例如心率 2A37 需按 flags 判断 8/16 位,电量 2A19 取首字节)。
- 写值时根据 characteristic.properties 选择类型:优先 .withResponse(若支持 .write),否则在支持 .writeWithoutResponse 且 peripheral.canSendWriteWithoutResponse 时用 .withoutResponse;用 peripheral.maximumWriteValueLength(for: type) 校验数据长度后再 writeValue(_:for:type:)。
- 在 didWriteValueFor 回调中处理 .withResponse 写失败;在 peripheralIsReady(toSendWriteWithoutResponse:) 中恢复排队的 .withoutResponse 写。
- 订阅用 setNotifyValue(true, for:),取消用 setNotifyValue(false, for:),并在 didUpdateNotificationStateFor 中确认 characteristic.isNotifying 状态。
- 作为外设时创建 CBPeripheralManager 并设置 delegate,在 peripheralManagerDidUpdateState 确认 .poweredOn 后,用 CBMutableCharacteristic(指定 type、properties、permissions)和 CBMutableService(primary: true)构建服务并 add(service)。
- 在 didAdd service 回调确认无错误后,调用 startAdvertising([CBAdvertisementDataServiceUUIDsKey: [serviceUUID], CBAdvertisementDataLocalNameKey: "MyDevice"]) 开始广播。
- 后台中心模式:扫描必须指定一个或多个服务 UUID(nil 仅前台可用),且扫描选项(含 CBCentralManagerScanOptionAllowDuplicatesKey)无效。
- 后台外设模式:不加 bluetooth-peripheral 时挂起后已发布服务内容会被禁用;后台不广播本地名称;服务 UUID 移到 overflow 区,需要显式服务扫描。
- 状态恢复(中心):创建 CBCentralManager 时传 CBCentralManagerOptionRestoreIdentifierKey,并实现 willRestoreState,从 CBCentralManagerRestoredStatePeripheralsKey 取回外设并重新设置 delegate 和强引用,从 CBCentralManagerRestoredStateScanServicesKey / CBCentralManagerRestoredStateScanOptionsKey 恢复扫描。
- 状态恢复(外设):创建 CBPeripheralManager 时传 CBPeripheralManagerOptionRestoreIdentifierKey,并实现 willRestoreState,从 CBPeripheralManagerRestoredStateServicesKey 和 CBPeripheralManagerRestoredStateAdvertisementDataKey 取回服务与广播数据并恢复应用状态。
- 避免常见错误:不要在 .poweredOn 前扫描/连接;不要不持有已发现外设的强引用;生产扫描不要传 nil 服务;不要在 didConnect 前开始服务发现;写值不要忽略特征属性和 maximumWriteValueLength 限制,.withoutResponse 必须受 canSendWriteWithoutResponse 约束。
- 按检查清单核对:用途描述、所有 BLE 操作以 .poweredOn 为门槛、强引用外设、生产用具体服务 UUID、discoverServices 前设置 delegate、读写/订阅前检查特征属性、写长度不超限、.withoutResponse 遵守 canSendWriteWithoutResponse、按需加后台模式、需要 BLE 事件重启时设置恢复标识并实现 willRestoreState、发现目标后停止扫描、处理断开并可选重连、写类型匹配特征属性。
适用边界 · 注意事项
- 需要隐私保护的外设发现/配对流程时,应先用 AccessorySetupKit,再回到 Core Bluetooth 做后续 GATT 通信。
- 只想做前台一次性扫描且不需要后台或状态恢复时,无需配置后台模式和恢复标识。