iOS BLE 开发(Swift 实现 + 面试 + 开发必备)
一、BLE 基础概念(必须懂)
1. BLE 是什么
Bluetooth Low Energy 低功耗蓝牙,特点:
-
低功耗、连接快、小数据传输
-
适用于:智能硬件、手环、车机、传感器、设备诊断
2. BLE 角色
-
Central(中心设备):手机(主动扫描、连接)
-
Peripheral(外设):硬件设备(被动广播、被连接)
3. BLE 通信核心结构
外设 → 服务 (Service) → 特征 (Characteristic)
-
Service:功能模块(UUID)
-
Characteristic:数据通道(读写 / 通知)
-
所有数据交互都通过 Characteristic 完成
二、iOS BLE 开发完整流程(Swift 标准 7 步)
1. 初始化 CBCentralManager
import CoreBluetooth
class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
var connectedPeripheral: CBPeripheral!
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: .main)
}
}
// 蓝牙状态回调
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("蓝牙已开启,可以扫描")
} else {
print("蓝牙不可用")
}
}
2. 扫描外设
// 开始扫描
func startScan() {
guard centralManager.state == .poweredOn else { return }
// 传入 nil 扫描所有设备,传入服务 UUID 可精准扫描
centralManager.scanForPeripherals(withServices: nil, options: nil)
}
// 扫描到设备
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi RSSI: NSNumber) {
print("发现设备:\(peripheral.name ?? "未知设备")")
// 记录设备、停止扫描、准备连接
}
// 停止扫描
func stopScan() {
centralManager.stopScan()
}
3. 连接外设
func connect(peripheral: CBPeripheral) {
connectedPeripheral = peripheral
connectedPeripheral.delegate = self
centralManager.connect(peripheral, options: nil)
}
// 连接成功
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("连接成功")
// 连接后自动搜索服务
peripheral.discoverServices(nil)
}
// 连接失败
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("连接失败:\(error?.localizedDescription ?? "")")
}
4. 发现服务
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard let services = peripheral.services else { return }
for service in services {
// 发现特征
peripheral.discoverCharacteristics(nil, for: service)
}
}
5. 发现特征
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
guard let characteristics = service.characteristics else { return }
for charac in characteristics {
print("特征UUID:\(charac.uuid)")
// 可根据 UUID 匹配读写/通知特征
}
}
6. 数据交互(核心)
① 读特征
func readCharacteristic(_ charac: CBCharacteristic) {
connectedPeripheral.readValue(for: charac)
}
// 读结果回调
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let data = characteristic.value {
let value = String(data: data, encoding: .utf8)
print("读取到数据:\(value ?? "")")
}
}
② 写特征
func writeData(_ data: Data, to charac: CBCharacteristic) {
connectedPeripheral.writeValue(data, for: charac, type: .withResponse)
}
③ 订阅通知(硬件主动推送)
func subscribeNotify(_ charac: CBCharacteristic) {
connectedPeripheral.setNotifyValue(true, for: charac)
}
// 取消订阅
func unsubscribeNotify(_ charac: CBCharacteristic) {
connectedPeripheral.setNotifyValue(false, for: charac)
}
// 通知数据回调(硬件主动发数据)
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let data = characteristic.value {
// 处理硬件推送的数据
}
}
7. 断开连接
func disconnect() {
if let peripheral = connectedPeripheral {
centralManager.cancelPeripheralConnection(peripheral)
}
}
// 断开回调
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("设备断开连接")
// 可在此处执行重连逻辑
}
三、GATT 机制详解(面试必问)
GATT = Generic Attribute Profile
BLE 数据交互的标准协议
规则:
-
以 Service 为功能单位
-
以 Characteristic 为数据单位
-
手机和硬件通过 读写 / 通知 交互数据
Characteristic 三种交互方式
-
Read:手机主动读
-
Write:手机主动写
-
Notify:硬件主动推送给手机(最常用)
四、断连重连机制(Swift 最稳定实现)
1. 监听断开(上面已实现)
2. 重连策略(直接用 UUID 重连,无需扫描)
// 存储设备 UUID
let storedUUIDString = "设备的identifier.uuidString"
// 重连方法
func reconnect() {
guard let uuid = UUID(uuidString: storedUUIDString) else { return }
let peripherals = centralManager.retrievePeripherals(withIdentifiers: [uuid])
if let peripheral = peripherals.first {
connectedPeripheral = peripheral
connectedPeripheral.delegate = self
centralManager.connect(peripheral, options: nil)
}
}
3. 重连失败 → 延迟重试 / 重新扫描
五、iOS 对 BLE 的强限制(非常重要!)
1. 扫描限制
-
后台扫描必须指定 Service UUID
-
后台扫描频率降低
-
不能无限扫描
2. 连接限制
-
最多同时连接 ~20 个设备(看系统)
-
连接失败不会自动重连
3. 后台运行限制
-
必须开启 Background Modes → Uses Bluetooth LE accessories
-
后台不能长时间扫描
-
后台写数据可能延迟 / 被挂起
4. 权限限制
-
iOS 13+:NSBluetoothAlwaysUsageDescription
-
iOS 14+:NSBluetoothPeripheralUsageDescription
-
不配置权限直接崩溃
5. 电池优化限制
-
系统会自动休眠 BLE
-
频繁扫描会导致耗电飙升
-
不用时必须停止扫描
6. 系统杀死 APP
-
后台超过一定时间会被系统 kill
-
被杀死后 无法自动重连(除非重新打开 APP)
六、iOS BLE 开发注意事项(Swift 避坑大全)
1. 必须判断 CBCentralManager 状态
状态未启用就扫描 → 直接无效
2. 不要连续调用 connect
-
连接中再次 connect → 系统报错
-
加
isConnecting标记位
3. 订阅通知前必须判断特征属性
if charac.properties.contains(.notify) {
// 允许订阅
}
4. 数据分包发送
BLE 单次最大传输 20 字节
超过必须分包、组包
5. 不要阻塞主线程
所有 BLE 回调都在子线程
UI 更新必须切主线程
DispatchQueue.main.async {
// 更新 UI
}
6. 多设备管理
用 UUID 作为唯一标识
不要用外设对象 / 名称
7. 处理设备信号弱
-
信号弱(RSSI < -80)会导致卡顿、断连
-
不要远距离操作
8. 释放逻辑
-
页面退出时:
-
停止扫描
-
取消连接
-
置空代理
防止内存泄漏、崩溃
-
七、面试高频 BLE 问题总结
-
BLE 经典蓝牙区别?
-
BLE GATT 结构?
-
Characteristic 三种交互方式?
-
iOS 后台 BLE 限制?
-
断连重连如何实现?
-
BLE 数据超过 20 字节怎么办?
-
iOS 13+ 蓝牙权限?
-
BLE 开发常见崩溃原因?
八、一句话总结(面试背诵)
iOS BLE 开发基于 GATT 协议,流程为:
初始化 → 扫描 → 连接 → 发现服务 → 发现特征 → 读写 / 通知 → 断开 / 重连。
iOS 对扫描、后台、权限、电量都有严格限制,开发必须注意线程、分包、重连、内存、权限、后台模式,才能保证稳定不崩溃。
更多推荐



所有评论(0)