SDK 与源码理解
蓝牙

一、蓝牙通信基础

1. 蓝牙通信的核心概念是什么?

蓝牙通信主要基于 BLE(Bluetooth Low Energy) 协议栈,由以下核心组件组成:

  • Central(中心设备):发起连接的设备,例如 iPhone。
  • Peripheral(外设设备):被连接的设备,例如手环或蓝牙传感器。
  • Service(服务):外设提供的功能集合,每个服务包含若干特征(Characteristic)。
  • Characteristic(特征):服务的最小数据单元,用于读写、通知数据。
  • Descriptor(描述符):附加在特征上的额外信息,如数据格式。

iOS 中使用框架 CoreBluetooth.framework 实现 BLE 通信。


二、CoreBluetooth 的主要类与职责

1. CBCentralManager

  • 负责扫描和管理外设(Peripheral)。
  • 常见方法:
    • scanForPeripherals(withServices:options:):扫描外设。
    • connect(_:options:):连接外设。
    • cancelPeripheralConnection(_:):断开连接。

2. CBPeripheral

  • 表示一个外设。
  • 可用于:
    • discoverServices(_:):发现服务。
    • discoverCharacteristics(_:for:):发现特征。
    • readValue(for:)、writeValue(_:for:type:):读写数据。
    • setNotifyValue(_:for:):订阅通知。

3. CBPeripheralManager

  • 用于将设备作为外设被其他中心设备连接。
  • 可广播自定义服务和特征。

三、蓝牙通信流程(Central 模式)

步骤:

  1. 创建并初始化 CBCentralManager;
  2. 扫描外设;
  3. 发现外设后调用 connect;
  4. 连接成功后发现服务;
  5. 发现特征;
  6. 通过读写或订阅特征进行数据交互;
  7. 根据需求断开连接。

简要代码示例:

class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
    var centralManager: CBCentralManager!
    var connectedPeripheral: CBPeripheral?

    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            central.scanForPeripherals(withServices: nil, options: nil)
        }
    }

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
                        advertisementData: [String : Any], rssi RSSI: NSNumber) {
        connectedPeripheral = peripheral
        central.connect(peripheral, options: nil)
    }

    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices(nil)
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        for service in peripheral.services ?? [] {
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        guard let data = characteristic.value else { return }
        print("Received:", data)
    }
}

四、蓝牙通信常见面试题

1. BLE 与传统蓝牙(Classic Bluetooth)区别?

项目BLEClassic Bluetooth
功耗极低较高
速度较低(1 Mbps)较高(3 Mbps)
适用场景IoT设备、可穿戴设备音频传输、文件传输
通信方式基于 GATT 协议(服务/特征)基于 RFCOMM 或 L2CAP

2. iOS 能否支持同时作为 Central 和 Peripheral?

可以。

CoreBluetooth 允许设备同时作为中心和外设工作(双模模式),但需注意资源冲突和后台模式配置。


3. 蓝牙通信中的 Notify 和 Indicate 区别?

  • Notify:外设主动推送数据,中心无需确认;
  • Indicate:外设推送数据后需要中心确认;
  • Notify 更快但不保证到达;Indicate 更安全但速度略慢。

4. 如何在后台保持蓝牙连接?

  • 在 Info.plist 中添加:
<key>UIBackgroundModes</key>
<array>
  <string>bluetooth-central</string>
</array>
  • 后台模式下,系统仍允许蓝牙事件回调,但扫描与连接策略会受到限制。

5. iOS 蓝牙断开重连的常见方案?

  • 在 didDisconnectPeripheral 回调中自动重连;
  • 可维护一个设备 UUID 列表,通过 retrievePeripherals(withIdentifiers:) 恢复连接;
  • 注意重连节流(避免无限重连导致系统惩罚)。

6. 数据传输速度慢如何优化?

  • 尽量合并数据包(MTU上限为20字节,iOS 14 后可提高到 512);
  • 使用 Notify 模式异步接收;
  • 调整 CBCharacteristicWriteType 为 .withoutResponse 提升写入效率;
  • 避免频繁发现服务和特征。

7. 蓝牙安全机制有哪些?

  • 配对(Pairing):建立安全连接;
  • 加密(Encryption):传输数据加密;
  • 授权(Authorization):用户确认访问权限;
  • iOS 对非认证蓝牙设备有严格权限控制,需在系统设置中授权。

8. 如何判断蓝牙是否可用?

通过 CBCentralManager 的 state 判断:

switch central.state {
case .poweredOn: print("可用")
case .poweredOff: print("蓝牙关闭")
case .unauthorized: print("无权限")
default: print("未知状态")
}

五、常见问题排查

问题可能原因解决方法
扫描不到设备外设未广播 / 权限未开检查外设状态、系统隐私设置
写入失败特征不可写 / 数据超长检查特征属性、分包发送
通知未触发未正确订阅调用 setNotifyValue(true, for:)
后台断连无后台模式 / 系统节能策略启用后台模式、合理设置重连逻辑

六、延伸思考

蓝牙在 iOS 的应用已不仅限于手环、音响,近年常见于:

  • 智能家居设备控制(HomeKit)
  • 蓝牙门锁、Beacon 定位
  • AR/VR 外设通信
  • 车载诊断(OBD)设备

理解 BLE 通信底层逻辑、数据交互模型与生命周期管理,是面试官考察的关键。


参考资料