我正在努力解决以下问题:当用户强制退出应用程序时,无法与BLE设备重新建立连接。 我的应用程序是这样的:
所有这些都可以通过将Bluetooth 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。
当用户强制退出应用程序时,它将发送本地推送通知,但不会重新建立连接。
我期待任何帮助。 谢谢!
答案 0 :(得分:3)
无需重新扫描设备;首次发现它时,应保存其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])
}
答案 1 :(得分:1)
如果用户不杀死应用程序,则无需让BLE充当信标。我的意思是,一旦外围设备断开连接,以便在可用时再次重新连接,您只需要在断开连接回调中再次调用connect,如果您的应用程序具有在后台作为中央运行的功能,则可以完美运行。这种行为似乎比iBeacon区域监视更可靠。
如果用户终止了您的应用程序,问题就开始了。您必须知道,这种行为是Apple设计的行为,我的意思是,如果用户杀死了您的应用程序,则它可能不想被某些设备的连接所困扰。
在这些情况下,唯一的解决方案似乎是使设备充当iBeacon。在这种情况下,如果检测到外围设备,则您的应用会在后台启动一小段时间。事实是,仅当您设置设备的特定服务CBUUID
时,后台扫描才有效。
已指定蓝牙中央背景模式的应用为 允许在后台扫描。也就是说,他们必须 通过在中指定服务来显式扫描一个或多个服务 serviceUUIDs参数。 CBCentralManager扫描选项被忽略 在后台扫描时。
为什么不只使用retrievePeripheralWithIdentifiers
?与设备建立连接后,将设置此UUID。
扫描是异步的,那么为什么要在调用扫描方法后尝试连接到外围设备?
您应该选择一种方式