Ios 更改后未正确重新发现CBR外围服务
我有一个iOS Swift 5项目,在该项目上使用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会抱怨服务已更改,但您没有处理这些更改的方法
CBCentralManager
连接到BLE
设备。有一个writeCBCharacteristic
,用于从iOS设备写入特定值,写入成功后,设备更改其服务,并将新服务添加到其GATT
表中。CoreBluetooth似乎无法识别更新的服务。BLE设备与iOS配对
尝试过的事情和发生的事情:
- 如果您没有从
实施cbperipheraldegate
,CoreBluetooth会抱怨服务已更改,但您没有处理这些更改的方法didModifyServices
- 如果实现
,则不会调用它,也不会显示上述消息didModifyServices
- 在成功写入后尝试手动重新查找服务,但
仅返回旧服务,尽管BLE设备现在在CBPerpiheral
表中实际有另一个服务,就好像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();返回
}
连接(外围设备)
}
专用功能扫描连接