首先,我的操作系统是OSX 10.10.4,iOS 4,Xcode 6.3.2,iPhone 6和Swift。
简单来说,我有一个特定的蓝牙LE设备,当Characteristic的值发生变化时,例如用户输入时,我希望能够接收到通知。尝试订阅它并不成功,而是会产生一个错误Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found."
长话短说,我有一个BluetoothManager类,在其中一旦我的$CBCentralManager.state
为.PoweredOn
,我就开始扫描外围设备。这很容易,我甚至是一个好公民,并专门扫描那些我想要的服务。
centralManager.scanForPeripheralsWithServices([ServiceUUID], options: nil)
希望这将成功,我实现了以下委托方法:
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {
if *this is a known device* {
connectToPeripheral(peripheral)
return
}
[...] // various stuff to make something a known device, this works
}
所以,继续前进,我们来到了:
func connectToPeripheral(peripheral: CBPeripheral) {
println("connecting to \(peripheral.identifier)")
[...] // saving the peripheral in an array along the way so it is being retained
centralManager.connectPeripheral(peripheral, options: nil)
}
好的,这个成功了,所以我收到确认消息并开始发现服务:
func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {
println("Connected \(peripheral.name)")
peripheral.delegate = self
println("connected to \(peripheral)")
peripheral.discoverServices([BluetoothConstants.MY_SERVICE_UUID])
}
这也是有效的,因为该委托方法也会被调用:
func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) {
if peripheral.services != nil {
for service in peripheral.services {
println("discovered service \(service)")
let serviceObject = service as! CBService
[...] // Discover the Characteristic to send controls to, this works
peripheral.discoverCharacteristics([BluetoothConstants.MY_CHARACTERISTIC_NOTIFICATION_UUID], forService: serviceObject)
[...] // Some unneccessary stuff about command caches
}
}
}
你猜怎么着:特征点被发现了!
func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) {
for characteristic in service.characteristics {
let castCharacteristic = characteristic as! CBCharacteristic
characteristics.append(castCharacteristic) // Retaining the characteristic in an Array as well, not sure if I need to do this
println("discovered characteristic \(castCharacteristic)")
if *this is the control characteristic* {
println("control")
} else if castCharacteristic.UUID.UUIDString == BluetoothConstants.MY_CHARACTERISTIC_NOTIFICATION_UUID.UUIDString {
println("notification")
peripheral.setNotifyValue(true, forCharacteristic: castCharacteristic)
} else {
println(castCharacteristic.UUID.UUIDString) // Just in case
}
println("following properties:")
// Just to see what we are dealing with
if (castCharacteristic.properties & CBCharacteristicProperties.Broadcast) != nil {
println("broadcast")
}
if (castCharacteristic.properties & CBCharacteristicProperties.Read) != nil {
println("read")
}
if (castCharacteristic.properties & CBCharacteristicProperties.WriteWithoutResponse) != nil {
println("write without response")
}
if (castCharacteristic.properties & CBCharacteristicProperties.Write) != nil {
println("write")
}
if (castCharacteristic.properties & CBCharacteristicProperties.Notify) != nil {
println("notify")
}
if (castCharacteristic.properties & CBCharacteristicProperties.Indicate) != nil {
println("indicate")
}
if (castCharacteristic.properties & CBCharacteristicProperties.AuthenticatedSignedWrites) != nil {
println("authenticated signed writes ")
}
if (castCharacteristic.properties & CBCharacteristicProperties.ExtendedProperties) != nil {
println("indicate")
}
if (castCharacteristic.properties & CBCharacteristicProperties.NotifyEncryptionRequired) != nil {
println("notify encryption required")
}
if (castCharacteristic.properties & CBCharacteristicProperties.IndicateEncryptionRequired) != nil {
println("indicate encryption required")
}
peripheral.discoverDescriptorsForCharacteristic(castCharacteristic) // Do I need this?
}
}
现在,直到这里的控制台输出如下所示:
connected to <CBPeripheral: 0x1740fc780, identifier = $FOO, name = $SomeName, state = connected>
discovered service <CBService: 0x170272c80, isPrimary = YES, UUID = $BAR>
[...]
discovered characteristic <CBCharacteristic: 0x17009f220, UUID = $BARBAR properties = 0xA, value = (null), notifying = NO>
control
following properties:
read
write
[...]
discovered characteristic <CBCharacteristic: 0x17409d0b0, UUID = $BAZBAZ, properties = 0x1A, value = (null), notifying = NO>
notification
following properties:
read
write
notify
[...]
discovered DescriptorsForCharacteristic
[]
updateNotification: false
嘿!它显示updateNotification
是false
。这是从哪里来的? 嗯,这是我setNotify...
的回调函数:
func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
println("updateNotification: \(characteristic.isNotifying)")
}
什么情况?我告诉它要通知我了!为什么它不通知我?让我们在带有println的行中设置一个断点,查看错误对象:
(lldb) po error
Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found." UserInfo=0x17026eac0 {NSLocalizedDescription=The attribute could not be found.}
好的,这让我无从下手了。我找不到关于这个错误代码的相关线索。我自己也无法理解描述,因为我尝试为我之前发现的一个特征设置通知,所以它必须存在,对吧?而且,在Android上似乎可以订阅通知,所以我想我可以排除设备问题……或者我可以吗?如果有任何关于此的线索,真的非常感谢!