我有一个iOS应用程序,它是我控制固件的外围设备的核心。一个类似的Android应用程序工作正常,能够连接到外围设备,发现服务,明确绑定,并读取加密的特征。
然而,在iOS上,CoreBluetooth API中没有明确的绑定。我的工作基础是,如果我想要结合,我应该只读取一个加密的特性,以强制发生粘合。
什么时候适合这样做?如果我在发现我想要阅读的特征时这样做,在这个函数中......
func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!)
...我从未收到外围设备的回调:didUpdateValueForCharacteristic。我相信,在这一点上阅读一个未加密的特征确实有用。
[编辑]
这是我的CBPeripheralDelegate实现的代码。
import CoreBluetooth
import CoreLocation
class BluetoothPeripheralController: NSObject, CBPeripheralDelegate {
private var _peripheral: CBPeripheral!
var peripheral: CBPeripheral! {
get {
return self._peripheral
}
set {
if self._peripheral != nil {
self._peripheral = nil
}
self._peripheral = newValue
if self._peripheral != nil {
self.peripheralDidChange(newValue)
}
}
}
private var notificationCenter: NSNotificationCenter = {
return NSNotificationCenter.defaultCenter()
}()
private var testModeCharacteristic: CBCharacteristic?
private var voltageCharacteristic: CBCharacteristic?
private var firmwareLoggingCharacteristic: CBCharacteristic?
static let voltageDidChangeNotification = "voltageDidChangeNotification"
static let testModeDidChangeNotification = "testModeDidChangeNotification"
static let bonded = "bonded"
static let firmwareLoggingDidChangeNotification = "firmwareLoggingDidChangeNotification"
func peripheralDidChange(peripheral: CBPeripheral) {
peripheral.delegate = self
}
func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) {
if error != nil {
log.error("Error: \(error)")
return
}
for service in peripheral.services {
log.verbose("Discovering characteristics for service: \(BleService().lookup(service.UUID))")
peripheral.discoverCharacteristics(nil, forService: service as! CBService)
}
}
// Hold on to characteristic instances so we can read/write/notify on them later.
func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) {
if let chars = service.characteristics as? [CBCharacteristic] {
log.verbose("* \(BleService().lookup(service.UUID))")
for char in chars {
log.verbose("** \(BleCharacteristic().lookup(char.UUID))")
if char.UUID.isEqual(BleCharacteristic.voltageCharacteristicUUID) {
voltageCharacteristic = char
}
if char.UUID.isEqual(BleCharacteristic.testModeCharacteristicUUID) {
testModeCharacteristic = char
log.verbose("Reading value for test mode.")
// Reading any encrypted value here does NOT result in a callback to peripheral:didUpdateValueForCharacteristic.
peripheral.readValueForCharacteristic(char)
}
if char.UUID.isEqual(BleCharacteristic.nordicNrfUartRxUUID) {
firmwareLoggingCharacteristic = char
}
}
}
}
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
if error != nil {
log.verbose("Error on value: \(error)")
return
}
let data: NSData = characteristic.value
log.verbose("Got value \(data) for characterisitc \(BleCharacteristic().lookup(characteristic.UUID))")
switch characteristic.UUID {
case BleCharacteristic.voltageCharacteristicUUID:
var voltage: Float = 0.0
data.getBytes(&voltage, length: sizeof(Float))
log.debug("Voltage: \(voltage)")
// The map view is interested in this.
self.notificationCenter.postNotificationName(BluetoothPeripheralController.voltageDidChangeNotification, object: self, userInfo: ["voltage": NSNumber(float: voltage)])
case BleCharacteristic.testModeCharacteristicUUID:
log.debug("Test mode: \(data). We are now bonded.")
self.notificationCenter.postNotificationName(BluetoothPeripheralController.bonded, object: self, userInfo: nil)
default:
log.debug("Unknown characteristic UUID: \(characteristic.UUID)")
}
}
func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {
if error != nil {
log.verbose("Error updating notification state: \(error)")
return
}
switch characteristic.UUID {
case BleCharacteristic.nordicNrfUartRxUUID:
log.verbose("Notification state change on firmware logging. Now notifying: \(characteristic.isNotifying)")
default:
log.verbose("Unhandled characteristic: \(characteristic.description)")
}
}
// Read/write
func readTestMode() {
if testModeCharacteristic == nil {
log.warning("Trying to read test mode before we have a characterisitc instance.")
return
}
// Calls back to peripheral:didUpdateValueForCharacteristic.
peripheral.readValueForCharacteristic(testModeCharacteristic)
}
}
答案 0 :(得分:1)
使用服务的didDiscoverCharacteristicsForService
属性确保characteristics
中存在所需的特征。
当您尝试在绑定之前读取字符时,您的外围设备会返回身份验证错误。如果你需要对它进行操作,错误将出现在didUpdateValueForCharacteristic
中,但仅错误就会触发绑定。
来自Bluetooth Accessory Design Guidelines:
如果出于安全原因,配件需要保税关系 对于Central,外设应该拒绝使用ATT请求 适当时,身份验证错误代码不足。
答案 1 :(得分:0)
原来可以在peripheral:didDiscoverCharacteristicsForService
期间读取一个特征值,而且我没有得到回调的唯一原因是iOS已经缓存了之前的绑定,但外围设备已经拥有了它自己的一面债券擦除。
解决方案是以下两者之一或两者:a)转到iOS设置应用程序并“忘记”外围设备和b)重新启动手机。