用户强制退出应用程序时重新连接蓝牙 4.0 连接
Reconnect Bluetooth 4.0 connection when user force quits the app
我正在努力解决这个问题,当用户强制退出应用程序时,我无法重新建立与我的 BLE 设备的连接。
我的应用程序是这样工作的:
- 首先启动应用程序,用户应该连接 BLE 设备 - 有效
- 当应用程序在后台时,连接仍在工作
- 如果我关闭 BLE 设备并再次打开,连接将重新建立 - 有效
- 当用户外出并返回家中时,连接将重新建立,并且用户会收到他靠近设备的通知 - 工作
所有这一切都通过将蓝牙 4.0 LE 变成 iBeacon 来解决。当用户足够近时,iBeacon 开始发送信号并触发 iOS 应用程序,用户收到推送通知,连接重新建立。
用户强制退出应用程序时出现问题。 iBeacon 仍然可以工作,因为当用户连接到 BLE 时,BLE 设备作为..蓝牙设备工作,但是当连接丢失时,BLE 作为 iBeacon 工作并通告 iOS 应用程序。
当用户强制退出应用程序时,用户会收到应用程序接近 iBeacon 的本地推送通知,因此这意味着应用程序将重新启动几秒钟(我认为是 10 秒),但我无法重新建立连接。
这是触发通知的代码,因为我希望在退出后重新连接 BLE。
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
// Check if the user's INSIDE the region, not outside...
guard state == CLRegionState.inside else { print("Error"); return }
if state == CLRegionState.inside{
let content = UNMutableNotificationContent()
content.title = "Device found!"
content.body = "You're close to your BLE Device, reestablish connection!"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "1389402823904", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (err:Error?) in
}
centralManager.scanForPeripherals(withServices: nil, options: nil)
let uuid = UUID(uuidString: "74278BDA-B644-4520-8F0C-720EAF059935")!
guard let mainPeripheral = mainPeripheral else {return}
centralManager.connect(mainPeripheral, options: nil)
centralManager.retrievePeripherals(withIdentifiers: [uuid])
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.centralManager.stopScan()
}
}
}
}
为简单起见,uuid 是硬编码的。
据我所知,当 iBeacon 发送信号时 didDeterminateState
被触发,我正在检查 CLRegionState
是否该区域在内部,这意味着靠近 iBeacon 本地通知的方法被触发,然后我需要重新扫描BLE 设备所以我调用 scanForPeripherals
但不是 connect
方法。 ScanForPeripherals
应该调用 didDiscover
方法:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
if peripheral.name == "DOPEY"{
peripheral.delegate = self
peripheral.discoverServices([HM_10_ServiceCharacteristic])
mainPeripheral = peripheral
centralManager.connect(peripheral, options: nil)
centralManager.stopScan()
}
}
当它找到 DOPEY
外设名称时,设备应该连接。
对于测试,我使用的是 HM-10 蓝牙 4.0 LE。
当用户强制退出应用程序时,它会发送本地推送通知但不会重新建立连接。
我期待任何形式的帮助。
欣赏!
无需重新扫描设备;您应该在第一次发现它时保存它的 identier
属性。然后,您可以使用 retrievePeripherals(withIdentifiers:)
尝试获取对 CBPeripheral
的引用。如果成功,只需调用 connect
.
你的代码显示了尝试做这样的事情,但你已经使用了(我认为是)你的服务 UUID,并且你没有对 retrievePeripherals(withIdentifiers:)
的结果做任何事情(你也赢了' 由于 guard
语句而达到此代码)。
你应该使用类似的东西:
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
// Check if the user's INSIDE the region, not outside...
guard state == CLRegionState.inside else { print("Error"); return }
let content = UNMutableNotificationContent()
content.title = "Device found!"
content.body = "You're close to your BLE Device, reestablish connection!"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "1389402823904", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (err:Error?) in
}
if self.mainPeripheral == nil {
let defaults = UserDefaults.standard
if let uuidString = defaults.string(forKey:"peripheralID"),
let uuid = UUID(uuidString: uuidString),
let peripheral = centralManager.retrievePeripherals(withIdentifiers: [uuid]).first {
self.mainPeripheral = peripheral
}
}
if let mainPeripheral = mainPeripheral
centralManager.connect(mainPeripheral, options: nil)
} else {
//TODO: Scan for peripheral. Note that you can't use `services:nil` in the background
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
if peripheral.name == "DOPEY" {
let defaults=UserDefaults.standard
defaults.set(peripheral.identifier.uuidString,forKey:"peripheralID")
peripheral.delegate = self
mainPeripheral = peripheral
centralManager.connect(peripheral, options: nil)
centralManager.stopScan()
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.discoverServices([HM_10_ServiceCharacteristic])
}
如果用户不关闭应用程序,您不需要让您的 BLE 充当信标。我的意思是,一旦外围设备断开连接并在可用时再次重新连接,您只需要在断开连接回调中再次调用连接,如果您的应用程序能够在后台 运行 作为中心,它将完美运行.这种行为似乎比 iBeacon 区域监控更可靠。
如果用户终止您的应用程序,问题就会出现。您必须知道这种行为是 Apple 设计的行为,我的意思是,如果用户终止了您的应用程序,它可能不想被连接到某些设备所困扰。
在这些情况下,唯一的解决方案似乎是让设备作为 iBeacon 工作。在这些情况下,如果检测到外围设备,您的应用程序会在后台启动一小段时间。事实上,仅当您为设备设置特定服务 CBUUID
时,后台扫描才有效。
Apps that have specified the bluetooth-central background mode are
allowed to scan while in the background. That said, they must
explicitly scan for one or more services by specifying them in the
serviceUUIDs parameter. The CBCentralManager scan option is ignored
while scanning in the background.
您为什么不只使用 retrievePeripheralWithIdentifiers
?一旦您连接到设备,就会设置此 UUID。
Scan 是异步的,为什么调用scan 方法后马上要连接外设?
你应该选择一种方式
我正在努力解决这个问题,当用户强制退出应用程序时,我无法重新建立与我的 BLE 设备的连接。 我的应用程序是这样工作的:
- 首先启动应用程序,用户应该连接 BLE 设备 - 有效
- 当应用程序在后台时,连接仍在工作
- 如果我关闭 BLE 设备并再次打开,连接将重新建立 - 有效
- 当用户外出并返回家中时,连接将重新建立,并且用户会收到他靠近设备的通知 - 工作
所有这一切都通过将蓝牙 4.0 LE 变成 iBeacon 来解决。当用户足够近时,iBeacon 开始发送信号并触发 iOS 应用程序,用户收到推送通知,连接重新建立。
用户强制退出应用程序时出现问题。 iBeacon 仍然可以工作,因为当用户连接到 BLE 时,BLE 设备作为..蓝牙设备工作,但是当连接丢失时,BLE 作为 iBeacon 工作并通告 iOS 应用程序。 当用户强制退出应用程序时,用户会收到应用程序接近 iBeacon 的本地推送通知,因此这意味着应用程序将重新启动几秒钟(我认为是 10 秒),但我无法重新建立连接。
这是触发通知的代码,因为我希望在退出后重新连接 BLE。
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
// Check if the user's INSIDE the region, not outside...
guard state == CLRegionState.inside else { print("Error"); return }
if state == CLRegionState.inside{
let content = UNMutableNotificationContent()
content.title = "Device found!"
content.body = "You're close to your BLE Device, reestablish connection!"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "1389402823904", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (err:Error?) in
}
centralManager.scanForPeripherals(withServices: nil, options: nil)
let uuid = UUID(uuidString: "74278BDA-B644-4520-8F0C-720EAF059935")!
guard let mainPeripheral = mainPeripheral else {return}
centralManager.connect(mainPeripheral, options: nil)
centralManager.retrievePeripherals(withIdentifiers: [uuid])
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.centralManager.stopScan()
}
}
}
}
为简单起见,uuid 是硬编码的。
据我所知,当 iBeacon 发送信号时 didDeterminateState
被触发,我正在检查 CLRegionState
是否该区域在内部,这意味着靠近 iBeacon 本地通知的方法被触发,然后我需要重新扫描BLE 设备所以我调用 scanForPeripherals
但不是 connect
方法。 ScanForPeripherals
应该调用 didDiscover
方法:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
if peripheral.name == "DOPEY"{
peripheral.delegate = self
peripheral.discoverServices([HM_10_ServiceCharacteristic])
mainPeripheral = peripheral
centralManager.connect(peripheral, options: nil)
centralManager.stopScan()
}
}
当它找到 DOPEY
外设名称时,设备应该连接。
对于测试,我使用的是 HM-10 蓝牙 4.0 LE。
当用户强制退出应用程序时,它会发送本地推送通知但不会重新建立连接。
我期待任何形式的帮助。 欣赏!
无需重新扫描设备;您应该在第一次发现它时保存它的 identier
属性。然后,您可以使用 retrievePeripherals(withIdentifiers:)
尝试获取对 CBPeripheral
的引用。如果成功,只需调用 connect
.
你的代码显示了尝试做这样的事情,但你已经使用了(我认为是)你的服务 UUID,并且你没有对 retrievePeripherals(withIdentifiers:)
的结果做任何事情(你也赢了' 由于 guard
语句而达到此代码)。
你应该使用类似的东西:
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
// Check if the user's INSIDE the region, not outside...
guard state == CLRegionState.inside else { print("Error"); return }
let content = UNMutableNotificationContent()
content.title = "Device found!"
content.body = "You're close to your BLE Device, reestablish connection!"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "1389402823904", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (err:Error?) in
}
if self.mainPeripheral == nil {
let defaults = UserDefaults.standard
if let uuidString = defaults.string(forKey:"peripheralID"),
let uuid = UUID(uuidString: uuidString),
let peripheral = centralManager.retrievePeripherals(withIdentifiers: [uuid]).first {
self.mainPeripheral = peripheral
}
}
if let mainPeripheral = mainPeripheral
centralManager.connect(mainPeripheral, options: nil)
} else {
//TODO: Scan for peripheral. Note that you can't use `services:nil` in the background
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
if peripheral.name == "DOPEY" {
let defaults=UserDefaults.standard
defaults.set(peripheral.identifier.uuidString,forKey:"peripheralID")
peripheral.delegate = self
mainPeripheral = peripheral
centralManager.connect(peripheral, options: nil)
centralManager.stopScan()
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.discoverServices([HM_10_ServiceCharacteristic])
}
如果用户不关闭应用程序,您不需要让您的 BLE 充当信标。我的意思是,一旦外围设备断开连接并在可用时再次重新连接,您只需要在断开连接回调中再次调用连接,如果您的应用程序能够在后台 运行 作为中心,它将完美运行.这种行为似乎比 iBeacon 区域监控更可靠。
如果用户终止您的应用程序,问题就会出现。您必须知道这种行为是 Apple 设计的行为,我的意思是,如果用户终止了您的应用程序,它可能不想被连接到某些设备所困扰。
在这些情况下,唯一的解决方案似乎是让设备作为 iBeacon 工作。在这些情况下,如果检测到外围设备,您的应用程序会在后台启动一小段时间。事实上,仅当您为设备设置特定服务 CBUUID
时,后台扫描才有效。
Apps that have specified the bluetooth-central background mode are allowed to scan while in the background. That said, they must explicitly scan for one or more services by specifying them in the serviceUUIDs parameter. The CBCentralManager scan option is ignored while scanning in the background.
您为什么不只使用 retrievePeripheralWithIdentifiers
?一旦您连接到设备,就会设置此 UUID。
Scan 是异步的,为什么调用scan 方法后马上要连接外设?
你应该选择一种方式