You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI开发iOS App通过蓝牙连接Raspberry Pi 4遇连接问题

问题诊断与修复方案

你的代码存在几个关键问题,导致连接后无法触发预期回调,看起来像是“连接失败”,实际是代理方法未被正确调用加上外设引用管理不当:

1. 代理方法签名错误

你写的didConnectPeripheral是旧Objective-C风格的Swift写法,不符合CoreBluetooth最新的代理方法签名,系统根本不会回调这个方法。正确的方法签名应该是:

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    // 连接成功后的逻辑
}

2. 未持有CBPeripheral强引用

在didDiscover里直接调用connect后,没有保存这个CBPeripheral实例的强引用,它可能被ARC释放,导致连接流程中断或后续服务发现失败。需要在BLEManager里添加属性持有已连接外设:

@Published var connectedPeripheral: CBPeripheral?

连接时赋值:

myCentral.connect(peripheral, options: nil)
self.connectedPeripheral = peripheral

3. 重复添加外设到数组

didDiscover会多次扫描到同一个外设,你的代码每次都往peripherals数组里添加,导致重复数据。可以通过外设identifier判断是否已存在,避免重复添加:

let isAlreadyAdded = peripherals.contains { $0.id == peripheral.identifier.uuidString }
if !isAlreadyAdded {
    let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, name: peripheralName, rssi: RSSI.intValue)
    peripherals.append(newPeripheral)
}

(建议把Peripheral的id改成外设uuidString,而非数组count,这样更准确)

完整修改后的代码示例

class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
    
    var myCentral: CBCentralManager!
    
    @Published var isSwitchedOn = false
    @Published var peripherals = [Peripheral]()
    @Published var connectedPeripheral: CBPeripheral? // 新增:持有已连接外设
    
    override init() {
        super.init()
        myCentral = CBCentralManager(delegate: self, queue: nil)
    }
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        isSwitchedOn = central.state == .poweredOn
    }
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? String ?? "Unknown"
       
        // 匹配目标外设UUID
        if peripheral.identifier.uuidString == "6D915395-3E79-0072-22A3-009DDC331F7C" {
            myCentral.stopScan()
            myCentral.connect(peripheral, options: [CBConnectPeripheralOptionNotifyOnDisconnectionKey: true])
            connectedPeripheral = peripheral // 持有引用
            print("开始连接目标外设")
        }
        
        // 避免重复添加外设
        let isAlreadyAdded = peripherals.contains { $0.id == peripheral.identifier.uuidString }
        if !isAlreadyAdded {
            let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, name: peripheralName, rssi: RSSI.intValue)
            peripherals.append(newPeripheral)
        }
    }
    
    // 修正后的连接成功回调方法
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.delegate = self // 发现服务/特征需设置peripheral代理
        peripheral.discoverServices(nil)
        print("连接成功:\(peripheral.name ?? "Unknown")")
    }
    
    // 新增连接失败回调,方便排查问题
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        print("连接失败:\(error?.localizedDescription ?? "未知错误")")
    }
    
    // 外设服务发现回调(可选,按需实现)
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        if let error = error {
            print("发现服务失败:\(error.localizedDescription)")
            return
        }
        peripheral.services?.forEach { service in
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }
}

// 修改Peripheral的id类型为外设UUID
struct Peripheral: Identifiable {
    let id: String
    let name: String
    let rssi: Int
}

额外排查点

  • 确认树莓派4的BLE服务正常广播,且无连接数量限制
  • 检查iOS设备蓝牙权限是否完全开启(设置->隐私与安全性->蓝牙)
  • 通过didFailToConnect回调的错误信息,直接定位连接失败原因

内容的提问来源于stack exchange,提问作者Arda Yasar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:54:28