CoreBluetooth:能否修改电池服务的电量值(而非iPhone自身电量)?
我正在开发一款用于QC/工程测试的应用,需模拟带电池的嵌入式系统,希望通过UISlider或UITextField设置任意电池电量值用于测试。但无论如何操作,Battery Level特征的值始终显示为iPhone自身的电量!
我最初的尝试是创建PeripheralManager对象,并添加默认的Battery Service和Battery Level Characteristic:
// ------INIT BATTERY SERVICE-------- batteryServiceCBUID = CBUUID(string:SRV_Battery ) let batteryService = CBMutableService(type: batteryServiceCBUID, primary: false) batteryLevelCharacterstic = CBMutableCharacteristic(type: CBUUID(string: CHK_BatteryLevel), properties: [ .read, .notify ], value: nil, permissions: [.readable, .writeable]) if let battChar = batteryLevelCharacterstic{ let batterylevelDescriptor = CBMutableDescriptor(type: CBUUID(string: DSK_BatteryLevel), value: value) battChar.descriptors = [batterylevelDescriptor] batteryService.characteristics = [ battChar] }
之后我像修改自定义特征一样修改该特征:
func setBatteryLevel(value:UInt8){ var passedValue = value let sampleBattLevel = Data(bytes: &passedValue, count: MemoryLayout<UInt8>.size) if let battChar = batteryLevelCharacterstic{ let success = peripheralManager.updateValue(sampleBattLevel, for: battChar, onSubscribedCentrals: nil) if(!success){ print(success) } } }
我在SO上了解到调用updateValue时外设可能未就绪,因此在代理方法中也调用了setBatteryLevel:
func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) { print("peripheralManager toUpdateSubscribers: \(String(describing: peripheral.description))") setBatteryLevel(value: 45) }
调试显示success为true,但中心设备仍未观测到特征值变化。我用相同流程修改自定义特征是成功的,请问该特征是否由系统提供无法修改?还是我的代码存在问题?
核心原因
系统自带的Battery Service(UUID 0x180F)是iOS系统托管的核心服务,优先级远高于你自定义创建的同名服务。你代码里创建的Battery Service直接被系统原生服务覆盖了,中心设备实际订阅、读取的是系统托管的Battery Level特征,所以始终显示iPhone真实电量;而你调用updateValue修改的是自己创建的特征,自然不会被中心设备感知到。
解决方案
改用自定义UUID(推荐)
放弃使用系统标准的Battery Service和Characteristic UUID,创建完全自定义的服务与特征。这样就能像之前修改自定义特征一样,完全控制电量值的更新,不会和系统服务产生冲突。尝试覆盖系统服务(兼容性有限)
如果必须使用标准UUID模拟(比如测试的中心设备仅识别标准服务),可以将你创建的Battery Service设置为primary: true,尝试抢占系统服务的优先级:let batteryService = CBMutableService(type: batteryServiceCBUID, primary: true)注意:这种方式在部分iOS版本中可能无效,因为系统会优先保留自身的原生服务。
确认服务识别情况
可以在中心设备上扫描所有服务,检查是否同时存在两个Battery Service(系统原生和你自定义的)。如果是,让中心设备明确订阅你自定义的特征即可,但这种方式需要中心设备配合修改逻辑。
内容的提问来源于stack exchange,提问作者jimBeaux27

