iOS10 上的蓝牙 LE 奇怪行为
Bluetooth LE on iOS10 strange behavior
我发现当 iPhone 正在更新本地特征值时,并且还听取了该特征的通知,即使 他就是那个人,他也会收到通知 更新了值,所以委托 :
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
将被调用,即使我是更改值的人,而不是远程服务器(ble 设备)。当远端发送数据时,我也会得到这个委托。 这是应该的方式吗?我不记得了。
我在 其他 扫描蓝牙 LE 的第三个应用程序上发现了相同的行为。
我还发现由于某种原因我的代码并不总是得到委托,也许我在这里做错了:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let foundName=peripheral.name
let deviceName = "Name"
if foundName?.range(of: deviceName) != nil
{
self.centralManager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
self.centralManager.connect(peripheral, options: nil)
NotificationCenter.default.post(name: Notification.Name(rawValue: "Bluetooth"), object: "Detected")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.discoverServices( nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services!
{
let thisService = service as CBService
print(thisService.uuid.uuidString)
if thisService.uuid.uuidString == serviceUUID {
peripheral.discoverCharacteristics(nil, for: thisService)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for charateristic in service.characteristics!
{
let thisCharacteristic = charateristic as CBCharacteristic
// check for data characteristic
if thisCharacteristic.uuid.uuidString == characteristicUUID {
print("REGISTERED CHARACTERISTIC:",thisCharacteristic)
self.peripheral.setNotifyValue(true, for: thisCharacteristic)
self.characteristic=thisCharacteristic
isConnected=true
NotificationCenter.default.post(name: Notification.Name(rawValue: "Bluetooth"), object: "Connected")
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.uuid.uuidString == characteristicUUID {
if let str = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)
{
print("BLE:DATAIN:",str )
NotificationCenter.default.post(name: Notification.Name(rawValue: "Bluetooth"), object: str)
}
}
}
func sendData(data:String)
{
if(peripheral != nil)
{
print("BLE:SENT")
var bytesData = [UInt8](data.utf8)
let writeData = NSData (bytes: &bytesData, length: bytesData.count)
peripheral.writeValue(writeData as Data, for: characteristic, type: CBCharacteristicWriteType.withoutResponse)
}
}
查了一天硬件芯片和iOS,发现notify update-有新值的时候会通知你
那么,什么是新值?
当上一个值与当前值不同时。
对于某些硬件配置,以前的值即使在重置后也会保留在缓存中,并且 iOS 会将其视为新值,即使硬件根本没有更新它 (!)
因此,当您注册通知时,iOS 将检查初始值 ,如果它包含 zero/nil 以外的其他内容,则委托将是打电话。
你的工作就是以某种方式清除芯片中以前缓存的值。
总的来说,我发现(也许为时已晚)最佳做法是连接并保持连接,只要应用程序处于 运行。这将消除每次需要发送数据时 connect/disconnect 发生的各种问题。
结论: 连接一次,当因任何原因断开连接时 - 自动重置您的硬件(使用主机控制器软件)
我发现当 iPhone 正在更新本地特征值时,并且还听取了该特征的通知,即使 他就是那个人,他也会收到通知 更新了值,所以委托 :
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
将被调用,即使我是更改值的人,而不是远程服务器(ble 设备)。当远端发送数据时,我也会得到这个委托。 这是应该的方式吗?我不记得了。
我在 其他 扫描蓝牙 LE 的第三个应用程序上发现了相同的行为。
我还发现由于某种原因我的代码并不总是得到委托,也许我在这里做错了:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let foundName=peripheral.name
let deviceName = "Name"
if foundName?.range(of: deviceName) != nil
{
self.centralManager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
self.centralManager.connect(peripheral, options: nil)
NotificationCenter.default.post(name: Notification.Name(rawValue: "Bluetooth"), object: "Detected")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.discoverServices( nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services!
{
let thisService = service as CBService
print(thisService.uuid.uuidString)
if thisService.uuid.uuidString == serviceUUID {
peripheral.discoverCharacteristics(nil, for: thisService)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for charateristic in service.characteristics!
{
let thisCharacteristic = charateristic as CBCharacteristic
// check for data characteristic
if thisCharacteristic.uuid.uuidString == characteristicUUID {
print("REGISTERED CHARACTERISTIC:",thisCharacteristic)
self.peripheral.setNotifyValue(true, for: thisCharacteristic)
self.characteristic=thisCharacteristic
isConnected=true
NotificationCenter.default.post(name: Notification.Name(rawValue: "Bluetooth"), object: "Connected")
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.uuid.uuidString == characteristicUUID {
if let str = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)
{
print("BLE:DATAIN:",str )
NotificationCenter.default.post(name: Notification.Name(rawValue: "Bluetooth"), object: str)
}
}
}
func sendData(data:String)
{
if(peripheral != nil)
{
print("BLE:SENT")
var bytesData = [UInt8](data.utf8)
let writeData = NSData (bytes: &bytesData, length: bytesData.count)
peripheral.writeValue(writeData as Data, for: characteristic, type: CBCharacteristicWriteType.withoutResponse)
}
}
查了一天硬件芯片和iOS,发现notify update-有新值的时候会通知你
那么,什么是新值?
当上一个值与当前值不同时。
对于某些硬件配置,以前的值即使在重置后也会保留在缓存中,并且 iOS 会将其视为新值,即使硬件根本没有更新它 (!)
因此,当您注册通知时,iOS 将检查初始值 ,如果它包含 zero/nil 以外的其他内容,则委托将是打电话。
你的工作就是以某种方式清除芯片中以前缓存的值。
总的来说,我发现(也许为时已晚)最佳做法是连接并保持连接,只要应用程序处于 运行。这将消除每次需要发送数据时 connect/disconnect 发生的各种问题。
结论: 连接一次,当因任何原因断开连接时 - 自动重置您的硬件(使用主机控制器软件)