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

相关推荐
冯汉栩2 小时前
Swift Control DateSelection(日期选择框)
ios·cocoa·swift
开心就好20254 小时前
appuploader-cli 使用教程:在 Windows 上用命令行把 IPA 上传到 App Store
后端·ios
冯汉栩5 小时前
Swift Control DashLineView(虚线)
开发语言·ios·swift
2501_915918416 小时前
iOS 真机调试工具推荐,安装运行、性能分析有哪些工具
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
游戏开发爱好者816 小时前
带签名时间戳接口的重放与压力测试实战,用动态值在发送前现算签名
网络协议·计算机网络·网络安全·ios·adb·https·压力测试
2501_916007471 天前
申请 iOS 推送证书并配置 APNs 群发推送教程
android·ios·小程序·https·uni-app·iphone·webview
weixin_403810131 天前
iOS自动化脚本怎么避免风控?无屏幕镜像截图原理详解
ios·自动化·跨境电商·苹果群控·苹果投屏·多媒体运营
wangruofeng1 天前
3 步把 MacBook 变成 7×24 远程主机,人在外面随时接管桌面
ios·agent·mac
weixin_403810131 天前
iOS免越狱自动化蓝牙HID方案:不装代理也能跑脚本
运维·ios·自动化·跨境电商·ai智能体·ios投屏·苹果投屏