Search code examples
iosmobileibeacon

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


I have a use case where there are 2 devices. One is a Apple Mobile phone running a IOS application and other is a BLE enabled IOT device.

  1. IOS Application continuously scans for nearby BLE Device and if it finds a BLE Device with a specific UUID service, it will connect to it and send data over GATT Characteristics.
  2. This IOS Application should run continuously even if it is in background. That is when it is in background, it should scan for BLE Devices with specific service and if it is found, it should connect to it in background and write GATT characteristics.
  3. Problem here is IOS terminates the application when App is in background.
  4. The only way is to make the IOT device broadcast IBeacon instead of normal BLE Beacon. But IOS application will get awaken in background if IBeacon is found, but it cannot get the BLE Address of the device which is sending IBeacon and cannot connect to it.

How can I address this problem?


Solution

  • 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.