Objective-C/iOS: Keeping bluetooth connection alive in the background - objective-c

I've been researching this for a couple of days now and looks like it's not possible to keep bluetooth connection alive while the phone goes to sleep or if the app is in the background. However, I have found one app that claims they can run all the time: RunKeeper app says:
What's New In Version 2.5.1.0
Support for tracking heartrate in the background with Wahoo heartrate
monitor.
Does anyone know how they manage to send heart rate data to the phone while the app is in the background?
UPDATE:
Got it working by adding an entry in my plist under "Required background modes" for "bluetooth-central".

You need to use the new Bluetooth Low Energy feature via the CoreBluetooth Framework
Also note this is available currently only on iPhone4S since the Bluetooth Low Energy capability is dependent on the Bluetooth hardware in the iPhone.

In Xcode 5 there is a section for Background Modes in the your app's capabilities. Set Background Modes to ON and check "Uses Bluetooth LE accessories"

Related

react-native-ble-plx: BLE Scanning in iOS Background & Suspended mode

Context
IOS Background and suspended mode
Library version: react-native-ble-plx 1.0.3
Platform: iOS.
Platform logs (XCode)
Expected Behavior
When the app is even in the background or suspended mode of ios, the callback of the startDeviceScan gets invoked.
Current Behavior
When the app is in the background or suspended mode of ios, the callback of the startDeviceScan never gets invoked. I assume there is never discovery event found yet, according to the apple ble doc. Is it possible to configure the 'startDeviceScan' to make the app scan in the background and suspended mode?
After a few research, I find something helpful related with ble scanning in ios background & suspend mode.
1.) Scanning is throttled down when iOS devices are in the background.
While scanning in the foreground will likely immediately discover a device advertising next to it, discovery in the background can take up to ~60 times longer. The iOS system makes no assumptions that the user would prefer one app to have better Bluetooth functionality than another (or that only one app wants to use it). And since it is shared functionality, they want users to have a uniform experience across apps. You should check out the technical specifications regarding Advertising and Scanning intervals to get a better idea of what Apple has to do under the covers.
2.) Your devices may have already discovered each other before entering the background.
We must remember that Apple disables the CBCentralManagerScanOptionAllowDuplicatesKeyscanning flag when we enter the background. Since you're not even specifying this flag, it defaults to NO anyways. So if they've even seen each other once, you will not get another callback when they are in the background.
3.) Respect the Limits of Advertising Data
Although advertising packets in general can hold a variety of information about the peripheral device, you may advertise only your device’s local name and the UUIDs of any services you want to advertise.  There are also limits as to how much space you can use when advertising data. When your app is in the foreground, it can use up to 28 bytes of space in the initial advertisement data for any combination of the two supported advertising data keys. If this space is used up, there are an additional 10 bytes of space in the scan response that can be used only for the local name. Any service UUIDs that do not fit in the allotted space are added to a special “overflow” area; they can be discovered only by an iOS device that is explicitly scanning for them. While your app is in the background, the local name is not advertised and all service UUIDs are place in the overflow area.

How reliable is Bluetooth BLE in combination with smartphones?

We are developing a system where we can open doors with a smartphone. The chosen technique for this is Bluetooth BLE. There is an app which needs to be active in the background for providing this “handles key system”. This app recognizes and connects automatically with the door to open it.
We have a working demo on 3 different iphone models and several different android phones. The exact details of these system are not important for my question.
For our project we are in talk with some investors who says the idea is great but the Bluetooth technique is not reliable enough. The don’t say on what point it isn’t reliable enough.
We need to prove that Bluetooth IS reliable for this situation so we are looking for some best practices where Bluetooth is uses in critical situation such as a transport or health sector. Some “official” papers from a professors or university is also welcome!
We also looking aslo for examples where comparable situations where locks or something else are opened “handless” with a smartphone.
Where can we find these information, firms, papers and so on? In one line: How can we prove that Bluetooth is stable and reliable for our purposal (using a smartphone which autoconnects to some device for authentication)
I hope someone can help us else our project will be canceled!
There is nothing wrong with the BLE technology itself regarding reliability. It's rather the hardware and software implementations that will define how reliable a solution will be.
After having worked with BLE for several years I can tell that most peripheral SoC solutions are very reliable. And if they for some reason crash, the firmware is usually rebooted and restored.
Android and iOS are often the ones to blame if something isn't reliable. The Bluetooth stack running on these OSes crash quite often or misbehave and it can be hard to recover from.
For Android, sometimes Bluetooth crashes and when you try to turn it on again in it just goes back to turned off state. To recover you have to reboot the phone. I must however say that if you manage to initiate a connection and don't get any errors it will often continue to run correctly. To avoid the Android system to kill your app while it's in the background you have to use a foreground service. On some phones, like Huawei, the user must also explicitly mark the app to not being killed by the system when it's running in the background. For Android, there are also many phones with different Bluetooth controllers and some have bugs other controllers don't have. For example I once got hand on a Sony Xperia Z3 phone which Bluetooth controller cancelled a pending connection when an LE scan (running in parallel) was cancelled, but according to the HCI log the pending connection was still going on. The peripheral was advertising but was never connected to the phone. Once the pending connection was explicitly cancelled and restarted, it connected immediately.
iOS is more problematic than Android if you want BLE to work in the background. iOS will kill your app when it has been in the background for some time. To get around that, they have something called "state preservation" which is their solution to wake up the app on an incoming Bluetooth event such as the peripheral connects or sends a notification. However there are many bugs and design decisions which will lead to that your app isn't being woken up. For example see https://forums.developer.apple.com/message/65953. If your app has been terminated and the user turns off and then turns on bluetooth (or the system restarts bluetooth due to internal errors), your app will not be woken up on an incoming Bluetooth event. Also, if a bug occurs in the Bluetooth stack (which happens quite frequently), your app will not be woken up and all the events will rather arrive to your app once the user manually opens it up.

iOS CoreBluetooth operating as a peripheral and central simultaneously in the background

I'm writing an app using CoreBluetooth in iOS8 that detects and connects to other phones using the app. I'm trying to figure out the best way to be able to create a connection while both apps are backgrounded, but have been having difficulty in the scenario where both phones are backgrounded + locked. I've followed the suggestions of this post:
How to detect nearby devices with Bluetooth LE in iOS 7.1 both in background and foreground?
I haven't been able to establish a connection when both phones are backgrounded + locked, but I've been able to get a connection where the peripheral and central are backgrounded + locked and I then unlock the central (central still in the background). When I unlock the peripheral though nothing happens. It also works when they are backgrounded but not locked.
So in order to allow a connection to be established when I unlock the "peripheral", I decided to create a central and peripheral on both phones to simultaneously scan and advertise. Whichever discovers the other first will then stop scanning/advertising and connect. I've run into problems with this method that are detailed in the following two questions:
Peripheral and central at the same time on iOS
iOS CoreBluetooth Simultaneous Peripheral and Central Managers
Basically, I think that when both of my devices try to connect to each other simultaneously, they get hung up on attempting to connect and didConnectPeripheral is never called on either of them (the last thing both of them displays is a message saying that they are attempting to connect). It has worked occasionally though so I'm also a little confused as to why there is a probabilistic nature to the connection. Does anyone have any suggestions on how to approach the problem? If there's a better way to establish a connection when both apps are backgrounded + locked, please let me know because that was my original problem.
Thanks!
Declare bluetooth-central and bluetooth-peripheral background modes in your Info.plist to act in both Central and Peripheral roles in background.

CoreBluetooth -- Discovery of BLE peripheral while device locked

I've noticed, that the discovery of a BLE peripheral seems to behave different (on the central-side) when the device is in the background compared to when it's in the background + locked.
Can someone confirm this or point me to more information/documentation?
To be more specific -- when my app (central) is transitioning into the background and to the home-screen, it continues to discover peripherals as intended, but when I press the Sleep/Wake-button and thereby lock the device, it stops discovering my peripherals. The app is not crashing or anything... in fact, when I unlock the device (back to the home-screen), it resumes discovering peripherals without a need to bring it back to the foreground. I also understand, that BLE is triggered less frequently when in the background, but in my case I watched it in locked state for well over an hour and it never triggered a discovery, but once I unlock it's back to normal.
I am looking for a solution, where I also am able to discover a peripheral, when the device (running as central) is locked.
Thanks for your help!
-H
Update...
Found an interesting post and thought I'd share: http://web.archiveorange.com/archive/v/lBeBkjSSTe5jAan6ufTX
Especially the observations (by Brian Fudge) are interesting...
A scanning device that is locked does not report any iOS peripherals that are also locked.
On some devices, like iPhone 5 and 5S, you only need to press the home button on the peripheral for the scanner to succeed and
peripherals to be reported.
On other devices, like iPad and iPod Touch, you have to press the home button and unlock the peripheral for the scanner to succeed and
peripherals to be reported.
A non-iOS device, such as an rMBP, can scan iOS peripherals that are in the background and locked.
All iOS devices can scan hardware peripherals (such as a health tracker) while the iOS device is in the background and locked.
Ok i got the same problem and manage to understand why. So basically when you are in background or with the device locked, your app will be able to discover a device only one time (you can get multiple discovery in the foreground with the flag CBCentralManagerScanOptionAllowDuplicatesKey, but it's ignore in background)
So my app discovered without problems any BLE peripherals when it was in background but as soon as i locked my device i was unable to detect them. I figured out that the peripheral's broadcast packet is too huge (it was send in 2 times). Reducing my peripheral broadcast packet seems to fix the problem. When locked, the iPhone seems to listen to advertisement packet sent in one time. In foreground or background it is able to listen to packets send in 2 times.
Hope this can help someone.

iOS 7 Core Bluetooth Peripheral running in background

What I want is for my iOS device to be advertising a Bluetooth LE service all the time, even when the app isn't running, so that I can have another iOS device scan for it and find it. I have followed Apple's backgrounding instructions here:
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonPeripheralRoleTasks/PerformingCommonPeripheralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH4-SW1.
I can get it to advertise in the foreground ok and sometimes in the background but it doesn't stay advertising all the time. If you have it setup to run in the background, shouldn't it start advertising even after a device restart, just like background location services automatically start working after a restart? Are their limitations to the backgrounding that are not listed (or hard to find) in Apple's docs? Does anyone have an example of a Core Bluetooth Peripheral advertising correctly in the background?
Thanks...
Background advertisement is possible if you add the bluetooth-peripheral backgrounding mode to the app's plist. Once you do that, your app will continue to receive the callbacks even if backgrounded.
The advertisement is a tricky beast as Apple implemented several optimizations to reduce the power consumption and these reduce the quality of the advertisement as soon as the app is backgrounded. Namely: the rate is reduced severely, the advertised services are not included and the local name is not included either. Once the app comes back to foreground, these restrictions are invalidated.
In the general case, this kind of backgrounded operation requires the app to be running. With iOS 7 the restoration process has been implemented that allows the OS to act on the app's behalf while it is terminated and restore the app when some transmission or other operation is imminent. This requires you to add the restoration key to the initialization options of the CBPeripheralManager/CBCentralManager. Starting your application once is still required but after that, iOS will continue to act as the BLE facade towards the centrals/peripherals.
UPDATE: I ran a loop on the Apple bluetooth-dev list as well with this question and found that Core Bluetooth managers were declared to be not able to restore after reboot. This is not described in any documentation but probably was mentioned in the WWDC videos. We should file a bug and replicate it to raise Apple's awareness.
The implementation can be founded here:
https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonPeripheralRoleTasks/PerformingCommonPeripheralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH4-SW5
Its very simply actually.
<CBPeripheralManagerDelegate>
#property (strong, nonatomic) CBPeripheralManager *peripheralManager;
...
- (NSDictionary*) advertiseNotBeacon {
CBUUID *myCustomServiceUUID = [CBUUID UUIDWithString:#"MY_UUID"];
CBMutableCharacteristic *myCharacteristic = [[CBMutableCharacteristic alloc] initWithType:myCustomServiceUUID
properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyNotify
value:nil permissions:CBAttributePermissionsReadable];
CBMutableService *myService = [[CBMutableService alloc] initWithType:myCustomServiceUUID primary:YES];
myService.characteristics = #[myCharacteristic];
self.peripheralManager.delegate = self;
[self.peripheralManager addService:myService];
return #{CBAdvertisementDataServiceUUIDsKey : #[myService.UUID],
CBAdvertisementDataLocalNameKey: #"MY_NAME"
};
}
...
[self.peripheralManager startAdvertising:[self advertiseNotBeacon]];
Doing this, you will start advertising a peripheral service.
Now, if you want to keep the service running in background, read the documentation in this link: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW1
Quick steps:
Open info.plist
Add a new par key/value
Required background modes
App shares data using CoreBluetooth
Apple says to ctrl + click on any key/value and add a add the following, but exactly the same as explained before.
UIBackgroundModes
bluetooth-peripheral
Dont forgot about the limitations of running the service in background:
The CBCentralManagerScanOptionAllowDuplicatesKey scan option key is ignored, and multiple discoveries of an advertising peripheral are coalesced into a single discovery event.
If all apps that are scanning for peripherals are in the background, the interval at which your central device scans for advertising packets increases. As a result, it may take longer to discover an advertising peripheral.
These changes help minimize radio usage and improve the battery life on your iOS device.