【IOS】CoreBluetooth

文章目录

      • [🧱 核心概念:你需要了解的四个关键词](#🧱 核心概念:你需要了解的四个关键词)
      • [🚀 开发实战:如何用你的iPhone连接一个BLE设备](#🚀 开发实战:如何用你的iPhone连接一个BLE设备)
        • [1. 前期准备:导入框架与申请权限](#1. 前期准备:导入框架与申请权限)
        • [2. 初始化中心管理器并检查蓝牙状态](#2. 初始化中心管理器并检查蓝牙状态)
        • [3. 扫描外围设备](#3. 扫描外围设备)
        • [4. 连接外围设备](#4. 连接外围设备)
        • [5. 发现服务与特征](#5. 发现服务与特征)
        • [6. 读写数据与订阅通知](#6. 读写数据与订阅通知)
      • [💎 总结与最佳实践](#💎 总结与最佳实践)

学习 iOS 的 CoreBluetooth 框架,主要是为了开发能与 蓝牙低功耗(BLE) 设备通信的 App。它不支持经典蓝牙的详细开发,比如连接蓝牙耳机。

下面是一份学习教程,会从核心概念讲起,再通过一个中心设备的完整开发流程,带你一步步上手。

🧱 核心概念:你需要了解的四个关键词

在开始编码前,先理解 CoreBluetooth 框架中的四个核心角色,这是后续开发的基础。

  • CBCentralManager (中心设备):你的 iPhone,作为"中心",主动扫描和连接其他蓝牙设备。
  • CBPeripheral (外围设备):你连接的蓝牙设备,如心率手环、智能灯泡,作为"外围"提供数据或服务。
  • CBService (服务) :外围设备能提供的某种功能,比如"心率监测服务"。
  • CBCharacteristic (特征) :服务里的具体数据点,比如"心率数值"这个特征,数据就是通过读写特征来完成的。

🚀 开发实战:如何用你的iPhone连接一个BLE设备

下面以最常见的中心模式(Central) 为例,展示如何让 iPhone 扫描、连接并读取一个 BLE 设备的数据。

1. 前期准备:导入框架与申请权限
  • 导入框架 :在需要用到蓝牙的 Swift 文件顶部,加入 import CoreBluetooth
  • 申请权限 :在 Info.plist 文件中,添加 NSBluetoothAlwaysUsageDescription 键,并填写向用户申请蓝牙权限时的提示语。
2. 初始化中心管理器并检查蓝牙状态

创建一个类,通常命名为 BluetoothManager,并遵循 CBCentralManagerDelegate 协议。

swift 复制代码
import CoreBluetooth

class BluetoothManager: NSObject, CBCentralManagerDelegate {
    var centralManager: CBCentralManager!

    override init() {
        super.init()
        // 初始化中心管理器,代理设置为 self,队列设为 nil 表示在主线程回调
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }

    // 必须实现的代理方法,用于检查蓝牙状态
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .poweredOn:
            print("蓝牙已开启,可以开始扫描")
            // 在这里可以调用开始扫描的方法
        case .poweredOff:
            print("蓝牙未开启,请打开蓝牙")
        case .unsupported:
            print("设备不支持蓝牙")
        default:
            print("蓝牙状态未知")
        }
    }
}
3. 扫描外围设备

在蓝牙状态确认为 .poweredOn 后,调用 scanForPeripherals 方法开始扫描。

swift 复制代码
func startScanning() {
    // withServices: nil 表示扫描所有设备,传入特定服务的 UUID 数组可以过滤结果
    // CBCentralManagerScanOptionAllowDuplicatesKey: false 表示不重复发现同一设备
    centralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
}

当扫描到设备时,会触发代理方法 didDiscover

swift 复制代码
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    print("发现设备: \(peripheral.name ?? "未知设备"), 信号强度: \(RSSI)")

    // 假设我们想连接名为 "MyDevice" 的设备
    if peripheral.name == "MyDevice" {
        // 找到目标设备后,停止扫描以节省电量
        centralManager.stopScan()
        // 发起连接
        centralManager.connect(peripheral, options: nil)
    }
}
4. 连接外围设备

连接的结果会通过以下代理方法反馈。

swift 复制代码
// 连接成功
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    print("成功连接设备: \(peripheral.name ?? "未知设备")")
    // 设置外围设备的代理,以便接收其服务、特征等信息
    peripheral.delegate = self
    // 开始发现设备提供的所有服务,传入 nil 表示发现所有服务
    peripheral.discoverServices(nil)
}

// 连接失败
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
    print("连接设备失败: \(error?.localizedDescription ?? "未知错误")")
}
5. 发现服务与特征

连接成功后,需要发现设备提供的服务,以及每个服务下的特征。这一步需要遵循 CBPeripheralDelegate 协议。

swift 复制代码
extension BluetoothManager: CBPeripheralDelegate {
    // 发现服务
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }
        for service in services {
            print("发现服务: \(service.uuid)")
            // 发现该服务下的所有特征,传入 nil 表示发现所有特征
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }

    // 发现特征
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        guard let characteristics = service.characteristics else { return }
        for characteristic in characteristics {
            print("发现特征: \(characteristic.uuid)")
            // 在这里可以对感兴趣的特征进行读取、写入或订阅通知
        }
    }
}
6. 读写数据与订阅通知

发现特征后,就可以进行数据交互了。

  • 读取数据peripheral.readValue(for: characteristic)
  • 写入数据peripheral.writeValue(data, for: characteristic, type: .withResponse)withResponse 表示需要设备确认。
  • 订阅通知peripheral.setNotifyValue(true, for: characteristic)。当特征值发生变化时,设备会主动发送通知,并在 peripheral(_:didUpdateValueFor:error:) 代理方法中接收。

💎 总结与最佳实践

  • 注意线程安全 :确保 UI 更新在主线程,可使用 DispatchQueue.main.async {}
  • 实现错误处理和重试:蓝牙通信不稳定,代码要有重试和错误处理机制。
  • 优化扫描策略 :找到目标设备后立即停止扫描,并通过 withServices: 参数过滤设备。
  • 处理大数据传输:BLE 单次数据包有限制,大数据需分包发送和重组。
  • 处理后台模式 :若需后台使用蓝牙,需在 Capabilities 中开启 Uses Bluetooth LE accessories

总的来说,学习 CoreBluetooth 最好的方法就是动手实践。可以从一个简单的"设备扫描器"开始,逐步加入连接、读写功能。遇到问题多查阅官方文档和社区资料,祝你学习顺利!

相关推荐
getapi14 小时前
1 在 macOS 电脑上更新 Flutter iOS 应用到 App Store
flutter·macos·ios
可乐鸡翅yeah_14 小时前
App WebView 加载 M3U8 流媒体踩坑,安卓 iOS 混合开发播放异常定位
android·ios·harmonyos·m3u8·m3u8在线播放
代码的小搬运工1 天前
KVO学习
学习·ios·cocoa
方白羽1 天前
为什么 Android 非要用 Intent 传值?
android·ios·harmonyos
dora1 天前
iOS开发新手的第一行代码
ios
用户38034165882971 天前
视频编辑器的滤镜图内核:Node/Pin 模型怎么设计,撤销重做怎么才不崩
ios
CocoaKier2 天前
苹果续费成功,几天后付费协议突然失效,导致线上苹果支付全部失败
ios·apple
深念Y2 天前
PVE 安装黑苹果并直通 Quadro P400
macos·ios·黑苹果·驱动·苹果·英伟达·p400
weixin-a153003083162 天前
7.Appium-ios端自动化
ios·appium·自动化
Anhty3 天前
2026九月最新变声器测评:iOS安卓双端适配,低延迟运行更稳定
android·人工智能·功能测试·ios·智能手机