andiamo con ordine: in esecuzione OSX 10.10.4, iOS 4, Xcode 6.3.2, iPhone 6, SwiftSottoscrizione per le notifiche da un CBCharacteristic non funziona
Breve storia: ho un certo dispositivo Bluetooth LE qui dal che voglio ricevere notifiche quando i valori di un cambiamento caratteristico, ad es per input dell'utente. Cercando di iscriversi ad esso non riesce, ma produce un errore Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found."
Lunga storia: Così, ho una classe BluetoothManager in cui mi metto scansione Peripherals non appena il mio $CBCentralManager.state
è .PoweredOn
. E 'facile, io sono anche un buon cittadino e scansione appositamente per quelli con il servizio che voglio
centralManager.scanForPeripheralsWithServices([ServiceUUID], options: nil)
sperando che questo avrà successo, ho implementato il seguente metodo delegato:
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
}
Così si muove lungo, si arriva a:
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)
}
Yupp, questo riesce, in modo da ottenere la conferma e iniziamo a scoprire il servizio:
func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {
println("Connected \(peripheral.name)")
peripheral.delegate = self
println("connected to \(peripheral)")
peripheral.discoverServices([BluetoothConstants.MY_SERVICE_UUID])
}
che funziona anche, dal momento che il metodo delegato viene chiamato così:
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
}
}
}
E che ne sai: la caratteristica ottiene scoperto!
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?
}
}
Ora l'uscita della console fino a qui si presenta così:
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
Hey! Dice updateNotification
è false
. Da dove viene? Perché, è il mio di callback per setNotify...
:
func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
println("updateNotification: \(characteristic.isNotifying)")
}
Che cosa dà? Ho detto di essere avvisato! Perché non sta avvisando? Fissiamo un punto di interruzione in linea con il println e estrarre l'oggetto di errore:
(lldb) po error
Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found." UserInfo=0x17026eac0 {NSLocalizedDescription=The attribute could not be found.}
OK, quindi questo mi lascia a corto di idee. Non ero in grado di trovare gli indizi pertinenti riguardo a quel codice di errore. La descrizione stessa non riesco a capire da quando ho provato a impostare la notifica per una caratteristica che ho scoperto prima, quindi lo deve esistere, giusto? Inoltre, su Android sembra possibile iscriversi per le notifiche, quindi credo di poter escludere problemi con il dispositivo ... o posso? Tutti gli indizi su questo sono veramente apprezzati!
Sembra che non si possa mantenere un riferimento alla periferica. Paulw11 ha un'ottima risposta per questo http://stackoverflow.com/questions/26377470/ios-corebluetooth-centralmanagerdidconnectperipheral-didfailtoconnectperiph –
No, lo sto facendo; L'ho lasciato fuori per brevità: ho degli array per periferiche nello stato scoperto, connesso e connesso e mi assicuro di mantenere la periferica nell'apposito durante l'installazione. – mss
Il tuo codice sembra a posto e potrebbe essere un grande sul tuo dispositivo o su iOS. Il mio strumento ideale per i test è l'app LightBlue. Puoi usarlo per scoprire la tua periferica e i tuoi servizi e vedere se è possibile impostare una notifica sulle tue caratteristiche. – Paulw11