ios - Reconnect Bluetooth 4.0 connection when user force quits the app
问题描述
I'm struggling with the problem which is, I can not reestablish the connection with my BLE Device when user force quits the app. My app works like this:
- First launch the app user should connect with the BLE Device - that works
- When app is in background the connections is still working
- If I turn off the BLE Device and turn on again the connection is reestablished - works
- When user goes out and turn back home the connection is reestablished and user gets notification that he is close to the Device - works
All of this is solved by turning Bluetooth 4.0 LE into iBeacon. When user is close enough an iBeacon starts sending signals and iOS app is triggered and user gets push notification an connection is reestablished.
The problem appears when user force quits the app. iBeacon still works because when user is connected to BLE the BLE device works as.. Bluetooth device, but when the connection is lost BLE works as iBeacon and advertise the iOS app. When user force quits the app the user gets local push notification that app is close to iBeacon so it means the app is relaunch for the couple of seconds (10s I think) but I can not with this reestablish connection.
This is the code for tigger the notification and as I hoped for BLE reconnection after fore quit.
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()
}
}
}
}
For the simplicity the uuid is hardcoded.
As I understand the didDeterminateState
is triggered when iBeacon sends signal and I am checking the CLRegionState
if the region is inside which means close to the iBeacon the method for local notifications gets triggers, then I need to rescan for BLE devices so I am calling scanForPeripherals
but not the connect
method. ScanForPeripherals
should call the didDiscover
method:
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()
}
}
When it founds DOPEY
peripheral name the device should connect.
For tests I am using HM-10 Bluetooth 4.0 LE.
When user force quits the app it sends local push notification but does not reestablish the connection.
I am looking forward for any kind of help. Appreciate!
解决方案
无需重新扫描设备;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])
}
推荐阅读
- git - 我将如何创建一个 git stash 并继续使用我隐藏的文件?
- ios - 在 textField 中写入时按钮消失!这个错误有什么帮助吗?
- javascript - 如何将视觉变量作为参数传递给java脚本
- c++ - 具有直接 QueryPerformanceCounter 值的时钟可以符合 C++ 标准吗?
- python - Opencv 无法导入容器
- html - 如何将我的按钮向右对齐并使标题居中?
- javascript - 检测用户启动的元素大小调整(不同于文档流大小调整)
- python - 为什么我的 wxPython 程序不工作?(内码)
- css - 将文件夹中的所有 SASS 文件编译为单个 CSS 文件
- javascript - 将 night-watch 从 1.3.2 升级到 1.3.4 打破了现有的测试,特别是在页面对象中