Ios 更改后未正确重新发现CBR外围服务

Ios 更改后未正确重新发现CBR外围服务,ios,swift,bluetooth-lowenergy,core-bluetooth,Ios,Swift,Bluetooth Lowenergy,Core Bluetooth,我有一个iOS Swift 5项目,在该项目上使用CBCentralManager连接到BLE设备。有一个writeCBCharacteristic,用于从iOS设备写入特定值,写入成功后,设备更改其服务,并将新服务添加到其GATT表中。CoreBluetooth似乎无法识别更新的服务。BLE设备与iOS配对 尝试过的事情和发生的事情: 如果您没有从cbperipheraldegate实施didModifyServices,CoreBluetooth会抱怨服务已更改,但您没有处理这些更改的方法

我有一个iOS Swift 5项目,在该项目上使用
CBCentralManager
连接到
BLE
设备。有一个write
CBCharacteristic
,用于从iOS设备写入特定值,写入成功后,设备更改其服务,并将新服务添加到其
GATT
表中。CoreBluetooth似乎无法识别更新的服务。BLE设备与iOS配对

尝试过的事情和发生的事情:

  • 如果您没有从
    cbperipheraldegate
    实施
    didModifyServices
    ,CoreBluetooth会抱怨服务已更改,但您没有处理这些更改的方法
  • 如果实现
    didModifyServices
    ,则不会调用它,也不会显示上述消息
  • 在成功写入后尝试手动重新查找服务,但
    CBPerpiheral
    仅返回旧服务,尽管BLE设备现在在
    GATT
    表中实际有另一个服务,就好像
    coreblutooth
    缓存旧服务而不实际重新查找它们一样
  • 已尝试断开并丢弃
    cbperipal
    实例,以便重新发现它并重新连接-在这种情况下,断开连接后再也无法重新发现该外围设备
有什么办法可以重新发现一项新服务吗

相关蓝牙代码:

enum BluetoothStateChange
{
    case unknown
    case unsupported
    case unauthorized
    case poweredOff
}

class BluetoothCentralService: NSObject
{
    var onStateChange: ((BluetoothStateChange) -> Void)?
    var onServicesScannedPeripheralsUpdate: ((_ peripherals: [UUID]) -> Void)?
    var onCharacteristicsDiscovered: ((_ peripheral: UUID, _ service: CBUUID, _ characteristics: [CBUUID]) -> Void)?
    var onCharacteristicWriteFinished: ((_ peripheral: UUID, _ characteristic: CBUUID, _ isSuccessful: Bool) -> Void)?
    var onCharacteristicReadFinished: ((_ peripheral: UUID, _ characteristic: CBUUID, _ value: Data?) -> Void)?

    private var connectingPeripherals = Set<CBPeripheral>()
    private var connectedPeripherals = Set<CBPeripheral>()
    private var servicesDiscoveredPeripherals = Set<CBPeripheral>()
    private var ignoredPeripherals = Set<CBPeripheral>()

    private let central: CBCentralManager
    private let logger: LoggerProtocol

    var rememberedDeviceUUID: UUID?

    init(central: CBCentralManager, logger: LoggerProtocol, rememberedDeviceUUID: UUID? = nil)
    {
        self.central = central
        self.logger = logger
        self.rememberedDeviceUUID = rememberedDeviceUUID

        super.init()

        central.delegate = self
    }

    func ignore(_ uuid: UUID)
    {
        guard
            let peripheral = connectedPeripherals.first(where: { $0.identifier == uuid })
                ?? servicesDiscoveredPeripherals.first(where: { $0.identifier == uuid })
        else {
            return
        }

        ignoredPeripherals.insert(peripheral)
        servicesDiscoveredPeripherals.remove(peripheral)
        central.cancelPeripheralConnection(peripheral)
    }

    func services(for uuid: UUID) -> [CBUUID]
    {
        return servicesDiscoveredPeripherals.first { $0.identifier == uuid }?.services?.map { $0.uuid } ?? []
    }

    func discoverCharacteristics(for peripheralUuid: UUID, service uuid: CBUUID)
    {
        guard
            let peripheral = servicesDiscoveredPeripherals.first(where: { $0.identifier == peripheralUuid }),
            let service = peripheral.service(with: uuid)
        else {
            return
        }

        peripheral.discoverCharacteristics(nil, for: service)
    }

    func write(
        to peripheralUuid: UUID,
        service serviceUuid: CBUUID,
        characteristic characteristicUuid: CBUUID,
        value: Data,
        type: CBCharacteristicWriteType
    ){
        guard
            let peripheral = servicesDiscoveredPeripherals.first(where: { $0.identifier == peripheralUuid }),
            let service = peripheral.service(with: serviceUuid),
            let characteristic = service.characteristics?.first(where: { $0.uuid == characteristicUuid })
        else {
            return
        }

        peripheral.writeValue(value, for: characteristic, type: type)
    }

    func read(from peripheralUuid: UUID, service serviceUuid: CBUUID, characteristic characteristicUuid: CBUUID)
    {
        guard
            let peripheral = servicesDiscoveredPeripherals.first(where: { $0.identifier == peripheralUuid }),
            let service = peripheral.service(with: serviceUuid),
            let characteristic = service.characteristics?.first(where: { $0.uuid == characteristicUuid })
        else {
            return
        }

        peripheral.readValue(for: characteristic)
    }
}

extension BluetoothCentralService: CBCentralManagerDelegate
{
    func centralManagerDidUpdateState(_ central: CBCentralManager)
    {
        switch central.state
        {
        case .resetting:
            break
        case .unknown:
            onStateChange?(.unknown)
        case .unsupported:
            onStateChange?(.unsupported)
        case .unauthorized:
            onStateChange?(.unauthorized)
        case .poweredOff:
            onStateChange?(.poweredOff)
            connectedPeripherals = []
            servicesDiscoveredPeripherals = []
            ignoredPeripherals = []
            onServicesScannedPeripheralsUpdate?([])
        case .poweredOn:
            scanRemembered()
        default:
            logger.log(.warning, "\(#function): Unhandled state type.")
        }
    }

    private func scanRemembered()
    {
        guard
            let uuid = rememberedDeviceUUID,
            let peripheral = central.retrievePeripherals(withIdentifiers: [uuid]).first
        else {
            scanConnected(); return
        }

        connect(peripheral)
    }

    private func scanConnected()
    {
        let connected = central.retrieveConnectedPeripherals(withServices: [])

        connectedPeripherals.formUnion(connected)
        connectedPeripherals.forEach { $0.discoverServices(nil) }

        scanNew()
    }

    private func scanNew()
    {
        central.scanForPeripherals(withServices: nil)
    }

    private func connect(_ peripheral: CBPeripheral)
    {
        guard
            !ignoredPeripherals.contains(peripheral),
            !connectingPeripherals.contains(peripheral),
            !connectedPeripherals.contains(peripheral),
            !servicesDiscoveredPeripherals.contains(peripheral)
        else {
            return
        }

        connectingPeripherals.insert(peripheral)
        peripheral.delegate = self

        central.connect(peripheral)
    }

    func centralManager(
        _ central: CBCentralManager,
        didDiscover peripheral: CBPeripheral,
        advertisementData: [String : Any],
        rssi RSSI: NSNumber
    ){
        guard
            !ignoredPeripherals.contains(peripheral),
            !connectingPeripherals.contains(peripheral),
            !connectedPeripherals.contains(peripheral),
            !servicesDiscoveredPeripherals.contains(peripheral)
        else {
            return
        }

        connect(peripheral)
    }

    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
    {
        connectingPeripherals.remove(peripheral)
        connectedPeripherals.insert(peripheral)

        peripheral.discoverServices(nil)
    }

    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
    {
        connectedPeripherals.remove(peripheral)
    }
}

extension BluetoothCentralService: CBPeripheralDelegate
{
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
    {
        guard error == nil else { return }

        servicesDiscoveredPeripherals.insert(peripheral)
        connectedPeripherals.remove(peripheral)

        onServicesScannedPeripheralsUpdate?(servicesDiscoveredPeripherals.map { $0.identifier })
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
    {
        onCharacteristicsDiscovered?(
            peripheral.identifier,
            service.uuid,
            service.characteristics?.compactMap { $0.uuid } ?? []
        )
    }

    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?)
    {
        onCharacteristicWriteFinished?(peripheral.identifier, characteristic.uuid, error == nil)
    }

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)
    {
        onCharacteristicReadFinished?(peripheral.identifier, characteristic.uuid, characteristic.value)
    }

    func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService])
    {
        // This never gets called if it's actually implemented here!
    }
}
enum BluetoothStateChange
{
案件不详
不支持的情况
未经授权的案件
机箱断电
}
类BluetoothCentralService:NSObject
{
var onStateChange:((BluetoothStateChange)->无效)?
var OnServiceScannedPeriphersUpdate:((u外围设备:[UUID])->无效)?
发现变量onCharacteristics:(((外围设备:UUID,u服务:CBUUID,u特征:[CBUUID])->Void)?
变量onCharacteristicWriteFinished:((uu外围设备:UUID,u特征:CBUUID,uu成功:Bool)->无效)?
变量onCharacteristicReadFinished:((uu外围设备:UUID,u特征:CBUUID,uuu值:数据?->Void)?
私有变量connectingPeripherals=Set()
private var connectedPeripherals=Set()
private var servicesDiscoveredPeripherals=Set()
私有变量ignoredPeripherals=Set()
私人出租中心:CBCentralManager
私有let记录器:LoggerProtocol
变量rememberedDeviceUUID:UUID?
init(中心:CBCentralManager,记录器:LoggerProtocol,rememberedDeviceUUID:UUID?=nil)
{
self.central=central
self.logger=记录器
self.rememberedDeviceUUID=rememberedDeviceUUID
super.init()
central.delegate=self
}
func忽略(uid:uuid)
{
警卫
let peripheral=connectedPeripherals.first(其中:{$0.identifier==uuid})
?servicesDiscoveredPeripherals.first(其中:{$0.identifier==uuid})
否则{
返回
}
忽略外围设备。插入(外围设备)
服务发现外围设备。删除(外围设备)
中央。取消外围设备连接(外围设备)
}
func服务(用于uuid:uuid)->[CBUUID]
{
return services discoveredperipherals.first{$0.identifier==uuid}?.services?.map{$0.uuid}???[]
}
func发现特性(用于外围设备UUID:UUID、服务UUID:CBUUID)
{
警卫
let peripheral=servicesDiscoveredPeripherals.first(其中:{$0.identifier==peripheralUuid}),
let service=peripheral.service(带:uuid)
否则{
返回
}
外围设备。发现特性(无,用于:服务)
}
函数写入(
到外围设备UUID:UUID,
服务serviceUuid:CBUUID,
特征UUID:CBUUID,
价值:数据,
类型:CBCharacteristicWriteType
){
警卫
let peripheral=servicesDiscoveredPeripherals.first(其中:{$0.identifier==peripheralUuid}),
let service=peripheral.service(带:serviceuid),
让characteristic=service.characteristics?.first(其中:{$0.uuid==characteristicUuid})
否则{
返回
}
peripheral.writeValue(值,for:characteristic,type:type)
}
func读取(来自外围设备UUID:UUID、服务服务UUID:CBUUID、特征特性UUID:CBUUID)
{
警卫
let peripheral=servicesDiscoveredPeripherals.first(其中:{$0.identifier==peripheralUuid}),
let service=peripheral.service(带:serviceuid),
让characteristic=service.characteristics?.first(其中:{$0.uuid==characteristicUuid})
否则{
返回
}
外围设备读取值(用于:特性)
}
}
扩展蓝牙中心服务:CBCentralManagerDelegate
{
func CentralManager数据状态(uCentral:CBCentralManager)
{
切换中央状态
{
案例.重置:
打破
案件.未知:
onStateChange?(.未知)
案例。不支持:
onStateChange?(.不支持)
案件.未经授权:
onStateChange?(.未经授权)
案例.断电:
onStateChange?(.poweredOff)
已连接的外围设备=[]
servicesDiscoveredPeripherals=[]
ignoredPeripherals=[]
OnServicesCannedPeripherationsUpdate?([])
案例.poweredOn:
扫描器()
违约:
logger.log(.warning,“\(#函数):未处理的状态类型。”)
}
}
私有函数
{
警卫
设uuid=rememberedDeviceUUID,
let peripheral=central.retrievePeripherals(带标识符:[uuid])。首先
否则{
scannonnected();返回
}
连接(外围设备)
}
专用功能扫描连接