iOS Bluetooth monitoring without iBeacon monitoring - ios

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.

Related

How to keep scanning for BLE sensors and Identify sensor keyEvent while iOS App is terminated

How to keep scanning for BLE Sensors while App is in the terminated status in IOS App. While App is running I am able to manage multiple sensors. However, when App is terminated, how to keep listening to an advertisement and connect the Sensor to App not running status.
State preservation and State Restoration is implemented. Background mode Bluetooth-Central is turned on
I want to achieve it like Tile and Chipolo are doing in the terminate state.
What you are trying to achieve is not possible with normal ble capabilities:
Apps that support background execution may be relaunched by the system to handle incoming events. If an app is terminated for any reason other than the user force quitting it, the system launches the app when one of the following events happens:
Refer to Understanding When Your App Gets Launched into the Background
The way tile works is by using the iBeacon standard (my best guess).
An iBeacon is substantially a BLE. Your app can start a Region Monitoring for an iBeacon receiving region events (enter, exit). These events would wake your app also if the user killed it. When your app is awaken by a region enter event you have 8 seconds (give or take) to execute code and react to the event. Within this time you can start a standard BLE connection to use your iBeacon as peripheral and keep your app reactive to BLE events.
Of course your peripheral must be designed to support such behaviour.

Syncing data over BLE via iOS without App Open (or in the background)

I'm working on a device that keeps count when a door is closed. What I'd like to do is when I walk through the door, my iPhone automatically syncs the data on the device and sends that count to the server (via iPhone) without me opening the app or having it in the background. Is this possible, if so how?
Here's a diagram of what I'm thinking:
Door closes -> BLE notifies iPhone -> BLE sends count to iPhone ->
iPhone sends that value to server
All without the user (me) touching my device or opening the installed iOS application.
Your app has to be running in the background to do something, but that is OK, because Core Bluetooth background mode will take care of that for you.
First, you need to select "Uses Bluetooth accessories" background mode in your project.
Now, your program flow will be something like this:
Your user runs your app which scans for available doors and displays them to the user
Your user selects a door that they want to connect to
You save the identifier of the selected peripheral somewhere like NSUserDefaults
You connect to the peripheral
Once you get a call to the didConnectPeripheral delegate method you can read the count and update your server once you get the value
The user can now suspend your app and do something else
Eventually the peripheral will go out of range and you will get a call to didDisconnectPeripheral. In this method you immediately re-issue the connect to the peripheral.
Since you have Core Bluetooth background mode, when the peripheral is eventually seen again you will get another call to didConnectPeripheral in the background, and you can proceed as per step 5 (In this case your app is already in the background so it will just go back to suspended state after you have read the data without the user doing anything).
You update the server in step 5. This step executes regardless of whether the app is in the foreground or background. The user doesn't need to open your app.
Now eventually iOS may remove your app from the suspended state, say due to memory pressure. In order to still be able to connect to the peripheral when it is seen you need to opt in to state restoration as described in the Core Bluetooth Programming Guide
If you are up for building your own circuit board and Bluetooth LE firmware, this is pretty straightforward:
Add a contact switch that sends a voltage level change to the circuit board whenever the door opens.
Increment a counter on the microcontroller when the level changes.
Write firmware that advertises an iBeacon packet with the counter as the least significant part of the iBeacon identifier (32 bit major and minor).
A phone can then pick up this counter by using CoreLocation APIs to both monitor for the beacon (for fast background wakeups) and range for it (to read the specific identifier), then sending the counter value to the server based on the identifier read.
The advantage of using CoreLocation instead of CoreBluetooth as #paulw11 suggests in his very good answer is faster background wakeups of the app, allowing an app to reliably read the counter in the background. With CoreBluetooth, this background wakeup can be much slower, and door open events are more likely to be missed.

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

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.

How does Venmo bring an app into the foreground in iOS for their iBeacon feature?

From http://blog.venmo.com/hf2t3h4x98p5e13z82pl8j66ngcmry/2014/7/8/introducing-background-nearby-with-ibeacons, they suggest that they were able to forcibly bring app into the foreground:
"Whenever a device enters a beacon region, it briefly launches the Venmo app into the foreground in order to broadcast its peer identifier over the MPC framework, thus establishing a Nearby connection. In other words, whenever our users open Venmo to pay or charge the people they are around, they can instantly emit a beacon signal that momentarily wakes up their friends’ devices to connect and populate the user's Nearby drawer."
Every post on here about this suggests this isn't possible. Can someone explain?
I suspect that "foreground" is a simplification and that Venmo actually takes advantage of the iOS location background capabilities (the iOS location background mode is also applicable to iBeacon); meaning the app doesn't actually enter the foreground, but is launched into the background to complete the necessary tasks even if the app has been terminated.
Here's a bit of info from the docs about iBeacon background usage: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW7

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