一、蓝牙通信基础
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 模式)
步骤:
- 创建并初始化 CBCentralManager;
- 扫描外设;
- 发现外设后调用 connect;
- 连接成功后发现服务;
- 发现特征;
- 通过读写或订阅特征进行数据交互;
- 根据需求断开连接。
简要代码示例:
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)区别?
| 项目 | BLE | Classic 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 通信底层逻辑、数据交互模型与生命周期管理,是面试官考察的关键。
参考资料