当前位置: 首页 > ai >正文

CoreBluetooth 入门:扫描并连接 BLE 手环实战


目录

  1. 为什么选择 BLE?

  2. 前置准备

    • 权限与 Capability
    • Info.plist 必填键
  3. CoreBluetooth 核心角色

  4. 创建 CBCentralManager

  5. 扫描附近设备

  6. 连接与断开

  7. 发现服务 / 特征

  8. 读写数据与订阅通知

  9. 重连、后台与省电策略

  10. 常见错误排查清单

  11. 结语


1. 为什么选择 BLE?

  • 超低功耗:手环、心率带等穿戴设备必须长续航。
  • 广播+连接双模式:无需事先配对,即可发现目标再建立安全会话。
  • 跨平台标准:遵循 Bluetooth 4.0+ GATT 规范,Android 与 iOS 均可互通。

2. 前置准备

2.1 打开 Capability

Xcode > Signing & Capabilities > +Capability > Background Modes → 勾选 Bluetooth LE Accessories(如需后台扫描/连接)和 Uses Bluetooth LE accessories.

2.2 Info.plist 键值

<key>NSBluetoothPeripheralUsageDescription</key>
<string>App 需要蓝牙权限以连接您的手环</string>
<key>UIBackgroundModes</key>
<array><string>bluetooth-central</string>
</array>

iOS 17 起,蓝牙权限提示分级更细;描述语必须说明具体用途,否则审核会被拒。


3. CoreBluetooth 核心角色

角色作用
CBCentralManager扫描、连接、管理外围设备
CBPeripheral代表单个外围 (手环)
CBService功能模块(如心率服务)
CBCharacteristic数据通道(读/写/通知)

所有交互都通过 委托(delegate)异步回调,无阻塞主线程。


4. 创建 CBCentralManager

import CoreBluetoothfinal class BLECenter: NSObject {private lazy var central = CBCentralManager(delegate: self,queue: .main,   // UI 友好options: [CBCentralManagerOptionShowPowerAlertKey: true])
}// MARK: - CBCentralManagerDelegate
extension BLECenter: CBCentralManagerDelegate {func centralManagerDidUpdateState(_ central: CBCentralManager) {guard central.state == .poweredOn else { return }  // 需蓝牙已开启startScanning()}
}

要点

  • central.state 值必须精确判断,.poweredOn 之前任何操作都无效。
  • 建议持有单例,避免多个 CBCentralManager 实例争抢硬件资源。

5. 扫描附近设备

private func startScanning() {// 仅侦听包含「通用心率服务」的设备,可降低功耗let heartRateServiceUUID = CBUUID(string: "180D")central.scanForPeripherals(withServices: [heartRateServiceUUID],options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
}// 回调:发现新外设
func centralManager(_ central: CBCentralManager,didDiscover peripheral: CBPeripheral,advertisementData: [String : Any],rssi RSSI: NSNumber) {print("发现 \(peripheral.name ?? "未知") @\(RSSI)dB")// 记录并发起连接self.targetPeripheral = peripheralcentral.stopScan()central.connect(peripheral, options: nil)
}
  • RSSI:信号强度,数值越接近 0 越近。
  • AllowDuplicatesKey:禁止重复回调,省电。

6. 连接与断开

func centralManager(_ central: CBCentralManager,didConnect peripheral: CBPeripheral) {peripheral.delegate = selfperipheral.discoverServices(nil)   // 拉取所有服务
}func centralManager(_ central: CBCentralManager,didFailToConnect peripheral: CBPeripheral,error: Error?) {print("连接失败:\(error?.localizedDescription ?? "未知")")
}func centralManager(_ central: CBCentralManager,didDisconnectPeripheral peripheral: CBPeripheral,error: Error?) {// 保证 UI 状态同步;如需自动重连,可在此处重新 connect
}

iOS 自动维护安全配对;若设备要求「配对码」,系统会弹出原生对话框,无需额外逻辑。


7. 发现服务 / 特征

func peripheral(_ peripheral: CBPeripheral,didDiscoverServices error: Error?) {guard error == nil else { return }peripheral.services?.filter { $0.uuid == CBUUID(string: "180D") } // 心率服务.forEach { peripheral.discoverCharacteristics(nil, for: $0) }
}func peripheral(_ peripheral: CBPeripheral,didDiscoverCharacteristicsFor service: CBService,error: Error?) {guard error == nil else { return }for characteristic in service.characteristics ?? [] {switch characteristic.properties {case _ where characteristic.properties.contains(.notify):peripheral.setNotifyValue(true, for: characteristic)case _ where characteristic.properties.contains(.read):peripheral.readValue(for: characteristic)default:break}}
}

8. 读写数据与订阅通知

func peripheral(_ peripheral: CBPeripheral,didUpdateValueFor characteristic: CBCharacteristic,error: Error?) {guard let data = characteristic.value, error == nil else { return }if characteristic.uuid == CBUUID(string: "2A37") { // Heart Rate Measurementlet bpm = parseHeartRate(from: data)print("当前心率:\(bpm) BPM")}
}private func parseHeartRate(from data: Data) -> Int {// Flag & 8 bit/16 bit 解析细节略return Int(data[1])
}func writeExample() {let command = Data([0x01, 0xFF])targetPeripheral?.writeValue(command,for: writeCharacteristic,type: .withResponse)
}
  • withResponse 确保写入成功回执,可提升可靠性。
  • 解析 GATT 规范文档,才能正确理解字节含义。

9. 重连、后台与省电策略

场景建议做法
App 进入后台开启 bluetooth-central 模式;必要时使用 scanForPeripheralsallowDuplicates = true 以便操作系统在后台唤醒。
断线重连didDisconnectPeripheral 里调用 connect(_:options:);或使用 CBCentralManagerstate restoration,系统会在 App 重启时恢复连接。
省电扫描完即停止 (stopScan);连接成功后关闭通知只读必须通道;避免每秒轮询写。

10. 常见错误排查清单

症状 / 日志可能原因解决方案
CBError.invalidStatecentral.state ≠ .poweredOn等待 centralManagerDidUpdateState
连接后立刻断开配对失败 / 密钥失效让用户删除系统配对记录,再尝试
didDiscoverServices 不回调外设只广播,不允许连接与厂商确认固件配置
特征写入返回 CBATTError.insufficientAuthentication需要加密连接确保外设开启 MITM 保护并正确配对

11. 结语

通过以上步骤,你已经完整走通了 扫描 → 连接 → 发现服务 → 读写特征 的 CoreBluetooth 主流程。掌握这些要点,便能快速与各类手环、传感器或智能硬件进行稳定通信。后续你可以:

  1. 深入研究 GATT Profile,理解行业标准特征数据;
  2. 实现 RSSI 滤波 + Proximity Trigger,优化用户体验;
  3. 结合 Combine / AsyncStream,让异步回调更加「Swifty」。

Happy Coding & Stay Connected 📶

http://www.xdnf.cn/news/7516.html

相关文章:

  • 安卓settings单双屏显示
  • Qt调用librdkafka
  • 基于ROS2/Gazebo的室内送餐机器人系统开发实战教程
  • 山东大学计算机图形学期末复习完结篇上——24历年题
  • 动力电池点焊机厂家:驱动新能源制造的精密力量|比斯特自动化
  • 5:OpenCV—直方图均衡化
  • MySQL 8.0 OCP 1Z0-908 161-170题
  • Go语言使用通义灵码辅助开发 - AI编程助手提升效率
  • PowerBI 矩阵实现动态行内容(如前后销售数据)统计数据,以及过滤同时为0的数据
  • 【jmeter】base64加密
  • RVTools 官网遭入侵,被用于分发携带 Bumblebee 恶意软件的篡改安装包
  • C++并发性能优化思路
  • [Vue]组件介绍和父子组件间传值
  • Linux下Docker使用阿里云镜像加速器
  • 企业级物理服务器选型指南 - 网络架构优化篇
  • 蓝桥杯5130 健身
  • 从代码学习数学优化算法 - 拉格朗日松弛 Python版
  • Mujoco 学习系列(二)基础功能与xml使用
  • SPA模式下的es6如何加快宿主页的显示速度
  • 《算法笔记》11.8小节——动态规划专题->总结 问题 D: Coincidence
  • 业务流程和数据结构之间如何对应
  • Java集合框架详解:单列集合与双列集合
  • Wan2.1 图生视频 支持批量生成
  • 【QT】类A接收TCP数据并通过信号通知类B解析
  • mac .zshrc:1: command not found: 0 解决方案
  • 从头实现react native expo本地生成APK
  • 无线通信基础
  • 适合初学者的机器学习路线图
  • 【Linux】第二十四章 管理网络安全
  • windows/linux 模拟鼠标键盘输入