gpt4 book ai didi

ios - 如何阻止 ios core-bluetooth CBCentralManagerDelegate 在 ios13 中断开连接

转载 作者:行者123 更新时间:2023-11-28 23:26:12 28 4
gpt4 key购买 nike

问题

我正在使用 core-bluetooth 以 6 Hz 的速率将传感器数据(64-128 字节的数组)传输到 iPad(第 6 代)。它在 ios 12 中运行良好。在我更新到 ios 13 后,蓝牙连接变得非常不可靠。该连接一次只能传输 20 个字节,并且会频繁断开连接(调用 centralManager(_ central: CBCentralManager, didDisconnectPeripheral...)并出现错误 Code=0 "Unknown error." UserInfo={NSLocalizedDescription=Unknown error.}。 .

在调试期间查看 iPad 屏幕,我注意到每次中心连接并发现我的服务时,在上述断开连接之前会弹出安全提示“Bluetooth Pairing Request: "<device-name>" would like to pair with your iPad. [Cancel] [Pair]”半秒钟。

所以似乎出于某种原因,核心蓝牙正在触发安全提示并且(我猜)延迟导致连接失败?奇怪的是这个提示发生了 19/20 次,但偶尔连接会在没有触发提示的情况下通过,并且在断开连接之前会收到几个缓冲区。

相关问题

another post关于类似的事情:如何防止 ios 13 中的权限请求,但看起来这更多是由于基于错误消息的外设。

a post详细说明 CBCentralManager didDiscover peripheral 中的缺失值字典,但无论如何我都没有使用那个值。

我肯定存储了对外围设备的硬引用,所以这不是这里的问题。我还打开了其他应用程序,可以让你浏览bluetooth4.0外设gatt服务器。 LightBlue、BLE Scanner 和 BLE Hero 在我的第 6 代 iPad 上都显示蓝牙连接提示,然后与外围设备断开连接。

我的实现

这个项目是学校类(class)的一部分。我在 gitlab 上有所有的代码。 The critical ios bluetooth code is below, and the project is on gitlab .


import Foundation
import CoreBluetooth

struct Peripheral {
var uuid: String
var name: String
var rssi: Double
var peripheral: CBPeripheral
}

class SensorsComputer: BLECentral {
// just a rename of below...
}

class BLECentral: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager: CBCentralManager!
var availablePeripherals: [String: Peripheral]
var sensorsConnected: Bool
var ref: CBPeripheral?
var sensorServiceUUIDs: [String]
var bleSensorComputerUUID: String
var data: [String:[UInt8]]
var dataNames: [String:[String:String]]

override init() {
data = [:]
availablePeripherals = [:]
sensorsConnected = false
ref = nil
sensorServiceUUIDs = ["5CA4"]
//bleSensorComputerUUID = "096A1CFA-C6BC-A00C-5A68-3227F2C58C06" // builtin is shit
bleSensorComputerUUID = "33548EF4-EDDE-6E6D-002F-DEEFC0A7AF99" // usb dongle

dataNames = [
// service uuids
"5CA4": [
// characteristic uuids
"0000": "LidarRanges",
],
]

super.init()
manager = CBCentralManager(delegate: self, queue: nil)
self.connect(uuid:bleSensorComputerUUID)
}

func scan(){
let services = dataNames.map { CBUUID(string:$0.key) }
manager.scanForPeripherals(withServices: services, options: nil)
}

func connect_internal_(uuid: String) -> Bool{ // TODO known bt device uuids.
if self.sensorsConnected {
// do not try to connect if already connected
return true
} else {
print(self.availablePeripherals.count)
if let found = self.availablePeripherals[uuid] {
manager.stopScan()
manager.connect(found.peripheral, options: nil)
return true
} else {
if availablePeripherals.count == 0 {
scan()
}
print("Error! no peripheral with \(uuid) found!")
return false
}
}
}

func connect(uuid: String){
let queue = OperationQueue()
queue.addOperation() {
// do something in the background
while true {
//usleep(100000)
sleep(1)
OperationQueue.main.addOperation {
self.connect_internal_(uuid: self.bleSensorComputerUUID)
}
}
}
}

func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
print("The central is powered on!")
scan() // automatically start scanning for BLE devices
default:
print("The centraol is NOT powered on (state is \(central.state))")
}
}

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
var name = ""
if let name_ = peripheral.name {
name = name_
}

let uuid = peripheral.identifier.uuidString
let rssi = Double(truncating: RSSI)
availablePeripherals[peripheral.identifier.uuidString] = Peripheral(uuid: uuid, name: name, rssi: rssi, peripheral: peripheral)
print(uuid, rssi)
}

func getSorted(uuids:Bool = false) -> [Peripheral] {
let peripherals = Array(availablePeripherals.values)
return peripherals.sorted(by:) {$0.rssi >= $1.rssi}
}

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Central connected!")
sensorsConnected = true
peripheral.delegate = self
var cbuuids:[CBUUID] = []
for id in sensorServiceUUIDs {
cbuuids.append(CBUUID(string: id))
}
peripheral.discoverServices(cbuuids) // TODO store service uuids somewhere nicer
}

func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
if let e = error {
print("Central disconnected because \(e)")
} else {
print("Central disconnected! (no error)")
}
sensorsConnected = false
availablePeripherals = [:]
}

func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("Central failed to connect...")
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
print("Peripheral could not discover services! Because: \(error.localizedDescription)")
} else {
peripheral.services?.forEach({(service) in
print("Service discovered \(service)")
// TODO characteristics UUIDs known
peripheral.discoverCharacteristics(nil, for: service)
})
}
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error = error {
print("Could not discover characteristic because error: \(error.localizedDescription)")
} else {
service.characteristics?.forEach({ (characteristic) in
print("Characteristic: \(characteristic)")
if characteristic.properties.contains(.notify){
peripheral.setNotifyValue(true, for: characteristic)
}
if characteristic.properties.contains(.read){
peripheral.readValue(for: characteristic)
}
if characteristic.properties.contains(.write){
peripheral.writeValue(Data([1]), for: characteristic, type: .withResponse)
}
})

}
}


func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
print("error after didUpdateValueFor characteristic \(characteristic): \(error.localizedDescription)")
} else {
let sname = characteristic.service.uuid.uuidString
let cname = characteristic.uuid.uuidString
guard let _dname = dataNames[sname], let dataName = _dname[cname] else {
return
}
//print("value of characteristic \(cname) in service \(sname) was updated.")
if let value = characteristic.value {
let value_arr = Array(value)
//print(" The new data value is \(value_arr.count) bytes long")
//print("dataname is \(dataName)")
self.data[dataName] = value_arr
}
}
}
}

BLE外设代码是一个基于bleno和rosnodejs的传感器数据节点项目。 The peripheral code is also on gitlab .

我已经在 git 中回滚到几个已知的工作项目版本,并且在更新到 ios 13 后似乎没有任何工作。我将尝试在 mac 项目上运行 corebluetooth 代码以测试它是否可以在那里工作。

问题

所以,综上所述,从ios 12.4更新到ios 13后,当连接到BLE外设时,即使通信是蓝牙4.0/BLE,也会打开蓝牙连接提示。随着这个提示,连接一开始就断开,有时给我一些部分数据缓冲区,有时什么都不给我。

BLE 连接未正确启动,如果连接提示正常工作,它会干扰我在没有用户输入的情况下自动连接到设备(机器人传感器)的能力。

如果有人知道 info.plist 中的某些选项可以防止出现此中断连接提示,那就太好了。我在这里不知所措,有没有简单的方法可以回滚 ios 版本?或者有什么方法可以让 Apple INC 发布紧急补丁,防止核心蓝牙低功耗的弹出窗口?或者有什么方法可以绕过弹出窗口并允许用户在不破坏 BLE 协议(protocol)的情况下正确进行身份验证?

感谢任何看过这篇文章的人。

最佳答案

我可能没有完整的解决方案,但这应该有助于指明正确的方向。

我假设代码在 Info.plist 中设置了 NSBluetoothAlwaysUsageDescription,这在 iOS 13 中现在是必需的。NSBluetoothPeripheralUsageDescription 在 iOS 13 之前是必需的。

您在消失前看到的提示是由配对过程引起的,可能由两件事触发:

  1. 外设尝试启动配对过程(discouraged by Apple in 25.10 of Accessory Design Guidelines)

  2. 该应用已尝试访问已加密但已被拒绝的特征。这会触发配对过程,从而触发弹出的警报。

在您点击“配对”按钮之前,有一些情况可能会导致连接断开。

  • 该应用未保留 CBPeripheral 引用(您表示它保留),如果是这种情况,您会看到一条 API 滥用日志消息。

  • 在您有机会做出响应之前,外围设备正在断开连接。这更有可能,您可以嗅探 BLE 数据包以确定。更多详细信息如下。

  • 可能存在计时问题,即应用程序在配对过程完成之前尝试继续处理请求,这可能会触发断开连接。要测试这种可能性,请在服务和特征发现完成后添加延迟,然后再发出额外的读/写/通知请求。

外围设备很可能正在断开连接,这可能发生在 key 交换过程中,如果 key 不匹配,则在您使用安全特性时会发生这种情况。如果 key 由于某种原因发生变化(我通常会在固件更新时看到它,也许外围设备发生了变化,可能是 iOS 更新到 13),那么这种行为就可能发生。如果您转到蓝牙设置并忘记了设备, key 将被丢弃,因此 key 交换过程可能会再次开始工作。如果是这样,则存在过时的 key ,很可能是在必须重新协商的 iOS 端。

最后的选择是暂时确保服务和特性不 protected 。我没有看到 secure: [...] 在你的代码中,所以我不确定。

如果简单的选项都无法修复它,我的下一步将是嗅探数据包。

关于ios - 如何阻止 ios core-bluetooth CBCentralManagerDelegate 在 ios13 中断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58645951/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com