Ble Device Keep Connect with iPhone When Application Terminate

IOS Application which can run in background and can connect to Device

While iBeacon is very fast at detecting in the background and works best, it is not absolutely necessary. You can detect a BLE service on iOS in the background and connect to it when it is discovered.

To do this you must:

  1. In your Info.plist declare:
    <key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
</array>

  1. In your AppDelegate in didFinishLaunching you must trigger a BLE scan start
centralManager?.scanForPeripherals(withServices: [myServiceUUID], options: nil)

If you do the above, after your app is terminated, iOS will auto-launch your app and you will get a callback to didDiscoverPeripheral when a new peripheral is discovered.

While this really does work, it is very difficult to test correctly because of the way iOS keeps track of duplicates. If a device has been detected already, and you kill your app you will not get a callback about its discovery -- iOS keeps track that it was already detected. It will only give you a launch and callback for a new device.

Here is how I would test it:

  1. Modify your app to send a local notification when it detects the BLE device. VERIFY THIS WORKS.
  2. Turn off your BLE device
  3. Launch your app
  4. Reboot your phone.
  5. Turn on your BLE device
  6. Wait for the notification above. Be patient! When you reboot your phone, the BLE stack may not be fully started for a few minutes.

The phone reboot step above is critical to clear out the cache of what devices the iPhone has already seen and are therefore ineligible for a callback.

Finally, you can accelerate this process with a BLE device that also advertises iBeacon as background detections are much faster and less temperamental. But as you note, you cannot use iBeacon to connect to a peripheral using CoreBluetooth. So you must advertise BOTH from your BLE device. This is a common approach I use all the time. Use iBeacon to accelerate the wake-up of your app and CoreBluetooth service advertisement detections to establish a connection.

Reconnect Bluetooth 4.0 connection when user force quits the app

There is no need to re-scan for the device; You should save its identier property the first time you discover it. You can then use retrievePeripherals(withIdentifiers:) to try and get the reference to the CBPeripheral. If you succeed, simply call connect.

Your code shows an attempt to do something like this, but you have used (what I presume is) your service UUID, and you aren't doing anything with the result from retrievePeripherals(withIdentifiers:) (You also won't reach this code because of the guard statement).

You should use something like:

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])
}

Launch app in background when BLE device is in range

In case of user forcibly kills the app by double clicking on home button and swipe out, it will not be relaunched until the user launches it again.

Coming to your case when Device is rebooted - Yes, you can configure State Preservation and Restoration to relaunch the app when user has not killed it forcibly before rebooting.

( Note: If the device requires a passcode to unlock, apps will not be relaunched until the device is unlocked for the first time after a restart )

Also, it is important to keep in mind that the app will be relaunched and restored if and only if it is pending on a specific Bluetooth event or action (like scanning, connecting, or a subscribed notification characteristic), and this event has occurred.

For more info:

Conditions Under Which Bluetooth State Restoration Will Relaunch An App



Related Topics



Leave a reply



Submit