Skip to content

01 - iOS 蓝牙与云服务全栈 ​

目录 ​

  1. Core Bluetooth 架构
  2. BLE 通信流程
  3. 蓝牙权限与适配
  4. Background Modes
  5. CloudKit 核心
  6. 后台任务
  7. 蓝牙与云服务 Android 对比
  8. 面试考点汇总

1. Core Bluetooth 架构 ​

1.1 CBPeripheralManager 和 CBCentralManager ​

Core Bluetooth 角色:

┌──────────────┐    ←─ 中央设备 (Central) ──→ 外设
│  CBCentral    │     (扫描、连接、请求服务)
│  Manager      │
└──────────────┘
          ⇅ BLE 通信 (GATT 协议)
┌──────────────┐    ←─ 外设设备 (Peripheral) ──→ 中央
│  CBPeripheral │     (广播、接收连接)
│  Manager      │
└──────────────┘

GATT 层级结构:
┌─────────────────────────┐
│       Service (服务)       │  ← 功能组
│   ┌───────────────┐      │
│   │  Characteristic │    │  ← 数据单元
│   │  (UUID + 值)     │    │
│   │  Properties:    │    │
│   │  - Read         │    │
│   │  - Write        │    │
│   │  - Notify       │    │
│   └───────────────┘      │
│   ┌───────────────┐      │
│   │  Characteristic │    │
│   └───────────────┘      │
└──────────────────────────┘

1.2 Central 设备(扫描连接) ​

swift
class BluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
    
    private var centralManager: CBCentralManager!
    private var connectedPeripheral: CBPeripheral?
    
    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: .main)
    }
    
    // MARK: - CBCentralManagerDelegate
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .poweredOn:
            centralManager.scanForPeripherals(
                withServices: [UUID(uuidString: "your-service-uuid")!],
                options: [CBCentralManagerScanOptionAllowDuplicatesKey: false]
            )
        case .poweredOff, .unsupported, .unauthorized:
            print("蓝牙不可用")
        default:
            break
        }
    }
    
    func centralManager(_ central: CBCentralManager,
                        didDiscover peripheral: CBPeripheral,
                        advertisementData: [String: Any],
                        rssi RSSI: NSNumber) {
        // 发现外设,可连接
        connectedPeripheral = peripheral
        peripheral.delegate = self
        central.connect(peripheral, options: nil)
    }
    
    func centralManager(_ central: CBCentralManager,
                        didConnect peripheral: CBPeripheral) {
        // 发现服务
        peripheral.discoverServices([UUID(uuidString: "your-service-uuid")!])
    }
    
    // MARK: - CBPeripheralDelegate
    
    func peripheral(_ peripheral: CBPeripheral,
                    didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }
        for service in services {
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral,
                    didDiscoverCharacteristicsFor service: CBService,
                    error: Error?) {
        guard let characteristics = service.characteristics else { return }
        for char in characteristics {
            if char.properties.contains(.notify) {
                peripheral.setNotifyValue(true, for: char)
            }
        }
    }
    
    func peripheral(_ peripheral: CBPeripheral,
                    didUpdateValueFor characteristic: CBCharacteristic,
                    error: Error?) {
        guard let data = characteristic.value else { return }
        // 处理接收到的数据
        print("收到数据: \(data)")
    }
    
    // 发送数据
    func sendData(_ data: Data) {
        guard let peripheral = connectedPeripheral else { return }
        // 找到可写的 characteristic
        peripheral.writeValue(data, for: characteristic, type: .withResponse)
    }
}

1.3 Peripheral 设备(广播数据) ​

swift
class PeripheralManager: NSObject, CBPeripheralManagerDelegate {
    
    private var peripheralManager: CBPeripheralManager!
    
    override init() {
        super.init()
        peripheralManager = CBPeripheralManager(delegate: self, queue: .main)
    }
    
    // MARK: - 广播服务
    func advertise() {
        let serviceUUIDs = [CBUUID(string: "your-service-uuid")]
        let advertisement: [String: Any] = [
            CBAdvertisementDataServiceUUIDsKey: serviceUUIDs,
            CBAdvertisementDataLocalNameKey: "MyDevice"
        ]
        peripheralManager.startAdvertising(advertisement)
    }
    
    // MARK: - CBPeripheralManagerDelegate
    
    func peripheralDidUpdateState(_ peripheral: CBPeripheralManager) {
        if peripheral.state == .poweredOn {
            // 添加服务
            let characteristic = CBMutableCharacteristic(
                type: CBUUID(string: "your-char-uuid"),
                properties: .read | .write | .notify,
                value: nil,
                permissions: .readable | .writeable
            )
            let service = CBMutableService(type: CBUUID(string: "your-service-uuid"), primary: true)
            service?.characteristics = [characteristic]
            peripheralManager.add(service!)
            peripheralManager.startAdvertising([
                CBAdvertisementDataLocalNameKey: "MyDevice"
            ])
        }
    }
    
    func peripheral(_ peripheral: CBPeripheralManager,
                    didReceiveWriteRequests request: [CBATTRequest]) {
        for req in request {
            // 处理写入请求
            req.value = req.value
            peripheral.respond(to: req, with: .success)
        }
    }
}

2. BLE 通信流程 ​

BLE 通信流程:

Central 设备:                              Peripheral 设备:
  ┌──────────┐                             ┌──────────┐
  │ 扫描外设  │───→ CBAdvertisementData ───→│ 广播数据  │
  │          │                              │          │
  │ 连接外设  │───→ L2CAP 连接 ────────────→│ 接收连接  │
  │          │                              │          │
  │ 发现服务  │───→ GATT Discover ────────→│ 注册服务  │
  │          │                              │          │
  │ 读写特征  │───→ GATT Read/Write ─────→│ 读写特征  │
  │          │                              │          │
  │ 订阅通知  │───→ GATT Notify ──────────→│ 推送通知  │
  └──────────┘                             └──────────┘

GATT 协议栈:
┌─────────────┐
│  Application │  BLE 应用层
│  Profile     │  (GATT Profile)
├─────────────┤
│  GATT        │  通用属性配置文件
├─────────────┤
│  ATT         │  属性传输协议
├─────────────┤
│  L2CAP       │  逻辑链路控制
├─────────────┤
│  HCI         │  主机控制接口
├─────────────┤
│  BLE Radio   │  蓝牙无线电
└─────────────┘

3. 蓝牙权限与适配 ​

3.1 Info.plist 配置 ​

xml
<!-- iOS 13+ -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要使用蓝牙连接设备</string>

<!-- iOS 12 及以下 -->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要使用蓝牙连接设备</string>

<!-- Core Bluetooth 无需额外权限声明 -->

3.2 蓝牙权限状态 ​

状态说明
.poweredOn可用
.poweredOff用户关闭
.resetting蓝牙重置中
.unauthorized应用无权限
.unsupported设备不支持
.restricted系统限制(家长控制)

3.3 最大传输单元 ​

BLE MTU(最大传输单元):

• 默认 MTU: 23 bytes (20 bytes payload + 3 bytes header)
• 协商 MTU: 通过 exchangeMTU 请求增大
• 典型协商结果: 150-512 bytes(取决于硬件)

// 请求增大 MTU
peripheral.maximumWriteValueLength(for: .withResponse)
// 有响应写入的最大长度

peripheral.maximumWriteValueLength(for: .withoutResponse)
// 无响应写入的最大长度

4. Background Modes ​

4.1 后台蓝牙模式 ​

Core Bluetooth 后台模式:

┌───────────────────────────────────────────┐
│ Info.plist → Background Modes → Bluetooth    │
│ LE accessories                                 │
├─────────────────────────────────────────────┤
│ • App 在后台时仍可扫描/连接外设               │
│ • 系统会重启你的 app 处理事件                  │
│ • 需实现 CBCentralManagerDelegate 的          │
│   centralManager:restorePeripherals          │
│   恢复外设列表                                │
└─────────────────────────────────────────────┘

恢复外设:
func centralManager(_ central: CBCentralManager,
                    restoreConnectedPeripherals profiles: [CBPeripheral]) {
    for peripheral in profiles {
        // 恢复连接状态
    }
}

5. CloudKit 核心 ​

5.1 CloudKit 架构 ​

CloudKit 架构:

┌───────────────────────────────────────────┐
│              CloudKit                       │
├────────────────────────────────────────┬──┤
│  Public Database   │  Private DB      │  │
│  (共享数据)        │  (用户私有)        │  │
├───────────────────┼────────────────┬──┤
│  CKRecord          │  CKRecord      │  │
│  CKQuery           │  CKQuery       │  │
│  CKSubscription    │  CKSubscription │  │
├───────────────────┼────────────────┬──┤
│  CKContainer       │  CKDatabase    │  │
│  (容器)            │  (数据库)       │  │
├───────────────────┼────────────────┬──┤
│  CKRecordZone      │  CKRecordZone  │  │
│  (记录区)          │               │  │
└───────────────────┴────────────────┴──┘

5.2 CloudKit 基本操作 ​

swift
import CloudKit

let container = CKContainer(identifier: "iCloud.com.your.app")
let publicDB = container.publicCloudDatabase
let privateDB = container.privateCloudDatabase

// 保存记录
let record = CKRecord(recordType: "User", recordID: CKRecord.ID())
record["name"] = "John"
record["age"] = 25

publicDB.save(record) { record, error in
    if let error = error {
        print("保存失败: \(error)")
    } else {
        print("保存成功")
    }
}

// 查询记录
let predicate = NSPredicate(format: "name == %@", "John")
let query = CKQuery(recordType: "User", predicate: predicate)
publicDB.perform(query, inZoneWith: nil) { results, error in
    for record in results ?? [] {
        if let name = record["name"] as? String {
            print("用户名: \(name)")
        }
    }
}

// 订阅记录
let subscription = CKRecordSubscription(recordType: "User")
subscription.events = .recordCreated
publicDB.save(subscription) { _, _ in }

6. 后台任务 ​

6.1 BGTaskScheduler ​

swift
import BackgroundTasks

// 注册后台任务
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.app.backgroundSync",
                                using: .main) { task in
    handleBackgroundSync(task: task as! BGAppRefreshTask)
}

func handleBackgroundSync(task: BGAppRefreshTask) {
    task.expirationHandler = {
        task.setTaskCompleted(success: false)
    }
    
    // 执行后台任务(最多 30 秒)
    performNetworkRequest { success in
        task.setTaskCompleted(success: success)
    }
}

// 调度任务
let request = BGAppRefreshTaskRequest(identifier: "com.app.backgroundSync")
request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)  // 15 分钟后
BGTaskScheduler.shared.submit(request)

6.2 后台任务类型 ​

类型用途最大时长
BGAppRefreshTaskApp 刷新30s
BGMaintenanceTask系统维护10s
BGProcessingTask长时间任务10min
UIBackgroundTask前台延迟3min

7. 蓝牙与云服务 Android 对比 ​

概念iOSAndroid/Kotlin
蓝牙Core Bluetooth (BLE)BLE API (BluetoothGatt)
角色Central/PeripheralDevice/Server/Client
GATTCBService/CBCharacteristicBluetoothGattService/Characteristic
云服务CloudKitFirebase / 自建后端
后台通信Background Modes + BLEForeground Service + BLE
数据同步CKSubscription + CloudKitFirebase Realtime DB

8. 面试考点汇总 ​

高频面试题 ​

  1. BLE 通信的核心概念?

    • Central/Peripheral 角色
    • Service → Characteristic 层级
    • Read/Write/Notify 三种操作
  2. iOS 蓝牙后台支持?

    • 需要配置 Background Modes
    • 系统自动恢复连接
    • CBCentralManagerDelegate 的 restorePeripherals 回调
  3. CloudKit 的数据库类型?

    • Public Database:所有用户共享
    • Private Database:用户私有
    • 记录通过 CKRecord 管理
  4. Background Tasks 有哪些类型?

    • BGAppRefreshTask:App 刷新(30s)
    • BGProcessingTask:长时间任务(10min)
    • BGMaintenanceTask:系统维护(10s)

面试回答模板 ​

"iOS 蓝牙用 Core Bluetooth 框架,Central 扫描连接 Peripheral,通过 Service/Characteristic 读写数据。支持后台模式,系统自动恢复连接。云服务用 CloudKit,分 Public 和 Private Database。后台任务用 BGTaskScheduler 调度。"


本文档对标 Android 30_Bluetooth + 31_Cloud_Background 的深度