iOS: Can a BLE device (not an iBeacon) wake up my app? - ios

Is it possible to associate a regular Bluetooth Low Energy device (not an iBeacon!) with my iPhone app so that when the device sends data my app gets woken up by the iPhone even if the iPhone is locked and the app is terminated (not even in the background)?

As long as your app specifies Bluetooth Central background mode then it will be woken if
Your app has a current connection to the device and it sends data (i.e. the device is in range and it notifies or indicates on a characteristic)
Your app has a pending connection to the device and it comes into range(i.e. the device was out of range, but you have called connect to automatically reconnect when it comes into range)
Your app was scanning for specific service types and a device advertising one of these service types comes into range
The case where you app is terminated is slightly different. For these scenarios to work in this case your app must implement state preservation and restoration
Core Bluetooth supports state preservation and restoration for apps
that implement the central role, peripheral role, or both.
When your
app implements the central role and adds support for state
preservation and restoration, the system saves the state of your
central manager object when the system is about to terminate your app
to free up memory (if your app has multiple central managers, you can
choose which ones you want the system to keep track of). In
particular, for a given CBCentralManager object, the system keeps
track of:
The services the central manager was scanning for (and any scan
options specified when the scan started)
The peripherals the central
manager was trying to connect to or had already connected to
The
characteristics the central manager was subscribed to
The Apple guide talks about the situation where your App is terminated due to memory pressure. It doesn't specify what happens if the app is terminated by the user "swiping up" in the app switcher - In many cases iOS takes this as an indication that the user doesn't want the app to run at all and won't restore it in this case.

There are two states for a bluetooth device to interact with your app:
It has never interacted with your app before
It has already connected to the use's device once and to the app once
In either case, an iBeacon device will be able to interact with your app.
If the device hasn't connected with your app before, I'm not entirely certain if there is a way to make it work. I have tried and failed to get it to wake up the app.
However, if the bluetooth device has connected before, then you can use CBCentralManager and its delegate methods to communicate between the device and your app.

Core Bluetooth should wake up your app from the OS if registered. Once awake, it's running in the background like normal. You have up to 3 minutes to perform whatever tasks you need to.

Related

corebluetooth and ios states

Successfully connected my BLE device using corebluetooth library and set notify values for certain service from it on my ios app. Works fine in foreground and background modes.
I currently save the identifiers of the device to UserDefaults and need the ios device to be always connected to the device at all times.
Question: What are the best practices for corebluetooth implementation with the states of the ios app? Specifically:
What should be implemented when user opens the app? (currently: I use the saved identifiers to reconnect to the ble device.. but is this necessary as corebluetooth should automatically stay connected to the device)
What should be implemented when the user backgrounds the app?
What should be implemented when the user reopens the app from background? (should i reconnect to the device?)
What should be implemented when the user kills the app? Does the corebluetooth connection get disconnected?
What should be implemented when battery is low and bluetooth is powered down or turned off by the device?
and lastly:
Is it necessary to implement the corebluetooth library in a singleton class to ensure that only one bluetooth manager is used by the app to connect to the devices?
Here are some advises and best (as I can see them) practices. These are not craved in stone:
When the user opens the app, it doesn't necessarily reconnects to the device. So your approach is good. However, you should check if the app wants to reconnect.
When the user backgrounds the app and the device is connected, the device stays connected. So nothing to implement here unless some special cases. We will get to them later.
When the user brings the app to the foreground (reopens it from background) and the device was connected before the app was sent to background, it still remains connected. So nothing to implement here.
When user kills the app, the device is disconnected, and there's nothing you can do. You can try to reconnect to the device when the user opens the app again.
I would monitor the device battery (check it once in a while) and when the battery reaches the critical level, let's say 5%, disconnect from the device.
And lastly: it is not necessary to implement it as a singleton. It is very convenient though when you have only one object that handles all the bluetooth connection. So, I'd say, singleton is a good choice.
In general you have to take into account two cases:
The app is killed by the system (probably because of memory pressure or crash). When the app is killed while in background, the system will relaunch it and the func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) function will be called. In this function you should try to reconnect to the bluetooth device. When the app is killed by the system while in foreground, sometimes (from my experience) the same function will be called. So you should do the same thing. When it's not called - see the following paragraph.
The app is killed by the user. In this case you cannot relaunch the app. But when the user opens it again you should check the latest connection status, and try to reconnect to the device if needed. Since you save the connected device in UserDefaults (which is the right thing), you should have all the needed properties.
For any other cases - disconnections because the Bluetooth turns off (on the device or on the phone) or because the device is out of range, the system handles the reconnection. So basically, nothing to do here.
Once again, all this is not carved in stone. That's how I implemented it, and it works fine.

iOS Bluetooth monitoring without iBeacon monitoring

I am trying to create an app that wakes up to background mode whenever it detects a new peripheral that advertises a pre-defined service. I want the wakeup to happen even if the user minimized the app, the app was suspended, the app was killed by the user or the app was killed by the system. Obviously I also want the app to be accepted to the app store (so don't suggest solutions like adding all possible UIBackgroundModes and run in the background forever...).
I can add bluetooth-central to the UIBackgroundModes because my app fits the description here - it needs to communicate with a peripheral in the background.
I found some documentation here about State Preservation and Restoration. It describes a scenario where an app connects to a bluetooth door lock, and the connection breaks because the user went far away from the door. From what I understand, when the user returns to the door and the iPhone detects the door lock (by its MAC address, I suppose), it reconnects to the door lock and wakes up the app in Background mode (please correct me if I am wrong).
I don't want to preserve a connection to the peripheral (and waste its battery). I want the app to run scanForPeripheralWithServices that will wake up the app when a new peripheral is detected, even if the app was killed\suspended by the user\system.
I found a relevant answer here to a different question, saying I could simulate an app-termination-by-the-OS using kill(getpid(), SIGKILL); and then, if my app uses State Preservation & Restoration, it should wake up (right?).
When my app detects a new\old peripheral, I want it to create a quick connection, read some characteristics and disconnect. Unforetunately this is not possible with iBeacon Monitoring that does not give a Peripheral object (only a region). I know I can detect the peripheral by running scanForPeripheralsWithServices after my app enters the iBeacon region, but this feels strange - a direct continuous scanForPeripheralsWithServices that survives suspension & kill, would make much more sense.
Any ideas?
If you know for sure that this is not possible, and depending on iBeacon Monitoring is the only way, please let me know.
The key part of the question is:
I want the app to run scanForPeripheralWithServices that will wake up the app when a new peripheral is detected, even if the app was killed\suspended by the user\system.
Unfortunately, this is not possible with CoreBluetooth alone. If the user kills an app, it will not get new OS launch events from CoreBluetooth unless the user manually launches the app again.
Fortunately, CoreLocation does not have this restriction. Since iOS 7.1, it will launch a killed app to notify it of a Bluetooth beacon detection. This would allow you a few seconds of background running time to scan for peripherals.

Activating an iOS app when Bluetooth connection connects

Is such a thing possible? I know certain apps such as VOIP apps have permission to run constantly, but I'm uncertain my app idea would be allowed to always run.
It depends on what you mean by "Activating an app".
You can operate as a Bluetooth Central in background mode and your app can receive notifications that a Bluetooth Low Energy service has been detected (if you are scanning for that service) or a device has connected (if you have a pending connect for that device).
You can then interact with the peripheral briefly (transfer a small amount of information for example) or display a notification to the user, but you cannot bring your app to the foreground preempting whatever the user is currently doing.
This project demonstrates CoreBluetooth background connection - https://github.com/paulw11/BTBackground

IOS: Can I periodically scan for dynamically changing BLE advertisement records in background?

Here is my scenario ..
I have a device that advertises dynamic data per BLE protocol. There are multiple such devices operating for a user
Questions -
1) Can IOS scan such constantly changing advertising data or does it expect advertising packets to be pretty static?
2) Can we create a service that scans for such packets periodically - maybe 30s every 5 minutes?
3) Can such a service be automatically restarted during bootup without user intervention?
You cannot create a service on a normal (non-jailbroken) phone. Isn't even possible to distribute something like that (read the app review guidelines). Sure, you can scan for BLE data on whatever interval you want, but your app needs to be active, or it needs to be doing something approved by Apple for making connections to BLE devices in the background. Just be aware that like any other background app, iOS might suspend or terminate your app at any time, and there's nothing you can do about it.
What you have described is covered by the standard BLE background mode - it is covered in the Core Bluetooth programming guide.
You can set up a scan for specific service UUIDs and this will continue in the background. Your app will be launched into the background when a device is discovered.
The exact scheduling of the notification can't be controlled - but in my experience you are notified pretty much as soon as a new peripheral is discovered. Once you have discovered a device you can even initiate a connection as soon as it disconnects (ie goes out of range) - iOS will automatically reconnect to the device when it comes back into range
In order for the scan or pending connection to survive across reboots you must configure state restoration. This is also covered in the Core Bluetooth Programming Guide.

How to wake up iOS app with bluetooth signal (BLE)

When using the BLE with CoreBluetooth (no iBeacon), is there a way to wake an app that is not running when the device receives a Bluetooth signal?
I'm simulating a beacon with the RedBearlab's BLE Shield (http://redbearlab.com/bleshield/).
Thanks,
DAN
* UPDATE 03/05/14 *
It looks like Apple has introduced a major update with iOS 7.1: now iOS will open your app for you if it detects a UUID that matches your app. The app only needs to be installed, it doesn't have to be running (logic in AppDelegate needed to answer the wake-up call).
If the app was running in the background and then closed (I mean here terminated - and you do not see it anymore in the list of background apps when you double click the home button) due to memory pressure from other apps, then the iOS will take care of waking it up again when a delegate is called (assuming you have background modes listed in .plist).
If the app was running in the background and then closed by the user (again I mean here terminated. So the user double clicked to get the list of apps running in the background and then clicked on your app in the background list until it wiggled and then pressed the 'x' next to the app to kill it) then this is a clear indication that the user does not want the app running in the background and the app will not be re-launched. The user has to relaunch the app for its delegates to start functioning again in the background (new in iOS7).
Update:
I am not sure if this is in the documentation but it is in CoreBluetooth WWDC 2013 Video. I recommend you watch it. They spent a good portion of the video on how CoreBluetooth behaves in the background.
From what I understand, if your app has not previously connected with the BLE Peripheral, then no.
If your app has previously connected with the BLE Peripheral, then use:
-connectPeripheral:options
Connection requests don't time out. The best place to call this method is when your app loses connectivity with the BLE peripheral. You will get notified when you lose connection to the peripheral in the CBCentralManagerDelegate Protocol:
-centralManager: didDisconnectPeripheral: error
So the next time your App comes in range of the BLE Peripheral, it will trigger this method. Also note that you will need to set up State Preservation and Restoration when you initialize a CBCentralManager.
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
the system wakes up your app when any of the CBCentralManagerDelegate or CBPeripheralDelegate delegate methods are
invoked, allowing your app to handle important central role events,
such as when a connection is established or torn down, when a
peripheral sends updated characteristic values, and when a central
manager’s state changes.
To perform certain peripheral role tasks while in the background, you
must include the UIBackgroundModes key with the bluetooth-peripheral
value in your app’s Info.plist file. When this key-value pair is
included in the app’s Info.plist file, the system wakes up your app to
process read, write, and subscription events.
You could try to declare voip in info.plist. For the time being, my application was automatically relaunched after a time, even user terminated it.

Resources