CoreBluetooth -- Discovery of BLE peripheral while device locked - objective-c

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.

Related

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.

Communication is lost on wifi toggle and onDisconnect and onPeersDisconnected not being fired

I'm using code from Google's sample game "ButtonClicker2000" found here: https://github.com/playgameservices/android-basic-samples
I have 3 androids running this game in genymotion plus one on my own phone, debugging them all from android studio. I've gotten to a point where I'm trying to gracefully handle disconnect in the event of network issues. The way I'm simulating network issues is toggling the wifi on my phone. (on or off, same behavior) After that, real time messages from my phone are no longer being received by the virtual devices, and my phone is no longer receiving real time messages from the other devices. However, my phone never enters onDisconnect() and the other devices never enter onPeersDisconnected. If I exit the app on my phone after communication ceases, onPeerLeft fires on the other devices.
How can I either ensure communication between devices in a game isn't lost in the likely event that a user at some point comes in or out of range of their wifi? If that's not possible, how can I at least ensure the onDisconnect event is firing from the offending device and onPeersDisconnected event is firing on the others?
If we're going with what the documentation states, onDisconnect usually happens when there's a problem with the remote services (crash or resource problem). having the WiFi turned off doesn't look like it fits with those criteria. [onPeersDisconnected](https://developers.google.com/android/reference/com/google/android/gms/games/multiplayer/realtime/RoomStatusUpdateListener#onPeersDisconnected(com.google.android.gms.games.multiplayer.realtime.Room, java.util.List)) is called when the participants are disconnected from the room.
Determine if the onP2PConnected is called when its connected and onP2PDisconnected when disconnected (hopefully this can catch WiFi toggling cases) since I think its more appropriate when you're using real-time multiplayer.
You can also read more about it in the Real-time Multiplayer section of the documentaiton.
Hope this helps!

iOS 9.1 BLE Connects and Immediately Disconnects

When I connect to a BLE peripheral using encryption on iOS 9.1 using a iPhone 6S the BLE peripheral is immediately disconnected. I've verified that this works on iOS 8 and 9.02. I've validated that the CBCentralManager didConnect delegate method is being called and a valid CBPeripheral object is being returned.
The BLE peripheral is disconnected immediately. I'm not able to even proceed to discover any services or characteristics before it is disconnected. The CBCentralManager didDisconnect method is called, but no error is returned.
Is anyone else seeing this? This has been working correctly for over a year and like I said it's only happening when using iOS 9.1 on the iPhone 6S. Don't have any other peripherals on 9.1 to test with.
UPDATE
According to Apple the issue is happening because we're not bonding the peripheral with the iPhone. So we've updated the firmware on the peripheral and are now bonding. This is presenting different issues surrounding maintaining bonding pairs between the phone and the peripheral. Our peripheral has a limited amount of memory, so we cannot maintain an infinite amount of bond references. To handle this scenario the peripheral allows for a maximum of 8 BLE bonds to be stored. When it receives a ninth request the first bond is removed from the peripherals list of bonded devices. This presents an issue because the iPhone doesn't know this bond has been removed and when I try to connect with the first device and interact with a characteristic I'm not prompted to pair. Which from my understanding is what kicks off the encryption process.
I'm wondering if there is anyway to remove a bond / device from an iPhones list of bonded devices, other then going into the Bluetooth settings and 'Forgetting' the device.
UPDATE #2
Apple has confirmed that there is NOT a way to remove a bonded peripheral from the 'MY Devices' section within the Bluetooth settings in the application due to security issues.
Based on this the scenario has now turned into the following. The iOS device has a reference to what was once a bonded peripheral under "My Devices" however that peripheral no longer has a reference to the iOS device within it's bonded devices table.
When I attempt to connect the iOS device, which still has the bond reference in it, to the peripheral that no longer has the bond reference we can connect successfully. However, after I connect successfully I discover the characteristic, set it to notify and receive no response and no pairing message. The only solution that fixes this issue is going into 'Settings' and 'Forgetting' the device and then attempting to reconnect.
Has anyone else experience this issue? Suggestions?
Thanks!

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.

Reducing memory size to ensure backgrounding in iOS

When developing an app that uses Bluetooth Low Energy, there comes a time when the iOS device loses connection to the peripheral. (Sometimes for hours.)
In order to reconnect to an existing peripheral, the app must constantly scan in the background at a specific rate throughout the day(s), even when the app is backgrounded.
The problem is, iOS will not guarantee that your app will not get killed, due to memory constraints, etc.
Information found in the iPhone OS Programming guide states that:
Apps that work with Bluetooth peripherals can ask to be woken up if
the peripheral delivers an update when the app is suspended. This
support is important for Bluetooth-le accessories that deliver data at
regular intervals, such as a Bluetooth heart rate belt. When an app
includes the UIBackgroundModes key with the bluetooth-central value in
its Info.plist file, the Core Bluetooth framework keeps open any
active sessions for the corresponding peripheral. In addition, new
data arriving from the peripheral causes the system to wake up the app
so that it can process the data. The system also wakes up the app to
process accessory connection and disconnection notifications.
The problem does not arise when the phone is connected to a device and the application is background. It does happen, however, when the device is disconnected and the app is backgrounded. In this specific case, the phone is no longer connected to the peripheral, and therefore no longer getting notifications.
Many people have discussed this before, either on Stack Overflow or the Apple forums, and I believe one of the Apple developers has responded saying:
We're aware of this issue and are trying to come up with a solution.
Currently, there is no workaround."
My question is, is there a way to at least improve your chances of not getting killed by iOS due to memory constraints?
For example, an instant messaging app (IMO) seems to run quite nicely in the background. After days and days of not being used, the app will wake up and display a gChat message.
I’m questioning things such as
Strong pointers
Overall memory size
Reducing memory size when app is backgrounded or minimized
Reducing frequency of background operation
Etc.
Why do you need background execution even when the bluetooth hardware is disconnected?
I don't think that you need to "rescan continuously" to reconnect again, if the hardware is "paired" with the iPhone/iPad, it will reconnect itself. Like a bluetooth headset. Or not?
AFAIK you have no chances to accomplish what you are asking for.
A normal App is always suspended when the user go back to home. The app has approx. 5 secs of background time to stop timers, save state ecc ecc.
There are special background modes that allows you to have more background time, and each of this mode (explained in the page you linked) has a different behavior.
About the bluetooth mode:
The descripted behavior is not an issue, but it's by design:
the app is suspended
when the app is suspended, it can be killed by the OS to free ram (and there are no tricks to avoid this), but the system will wake up if needed.
the app is then awaken every time a notification is received (awaken from suspended state or lauched from "previously-killed" state)
the app has 10 seconds to do tasks (save informations, ecc ecc). Moreover, can request +10 mins. of background time for a particular task
after the 10 secs (or 10 min) the app is suspended again
The example you wrote about the chat app is incorrect: chat apps usually doesn't use any background mode, simply they forward you messages using push notifications. When you open the app, the app connect to a server that stores all your messages and download it.
You can get "more uptime" using location background mode (routing app can work in background), or using a combination of significative location changes (the app is awaken) and the 10 minutes background time, but I think that Apple will reject an app that "abuse" this.
Shortly, you have to design your app to support this behavior.
I found this in some more Apple documentation:
Memory Usage for Background Apps
Every app should free up as much memory as is practical upon entering
the background. The system tries to keep as many apps in memory at the
same time as it can, but when memory runs low it terminates suspended
apps to reclaim that memory. Apps that consume large amounts of memory
while in the background are the first apps to be terminated.
Practically speaking, your app should remove strong references to
objects as soon as they are no longer needed. Removing strong
references gives the compiler the ability to release the objects right
away so that the corresponding memory can be reclaimed. However, if
you want to cache some objects to improve performance, you can wait
until the app transitions to the background before removing references
to them.
Some examples of objects that you should remove strong references to
as soon as possible include:
Image objects
Large media or data files that you can load again from disk Any other
objects that your app does not need and can recreate easily later To
help reduce your app’s memory footprint, the system automatically
purges some data allocated on behalf of your app when your app moves
to the background.
The system purges the backing store for all Core Animation layers.
This effort does not remove your app’s layer objects from memory, nor
does it change the current layer properties. It simply prevents the
contents of those layers from appearing onscreen, which given that the
app is in the background should not happen anyway. It removes any
system references to cached images. (If your app does not have a
strong reference to the images, they are subsequently removed from
memory.) It removes strong references to some other system-managed
data caches.
From the apple documentation i have always assumed the following:
connectPeripheral:options:
Establish a connection to the peripheral.
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options;
Parameters
peripheral
The peripheral to connect to.
options
A dictionary to customize the behavior of the connection. See CBConnectPeripheralOptionNotifyOnDisconnectionKey.
Discussion
**This never times out**. Use cancelPeripheralConnection: to cancel a pending connection.'
With the important part being on the fact that this never times out. I would assume this would hand off to the system so that it will connect automatically to the peripheral when it comes into range, thus removing the need for full backgrounding. Someone correct me if im wrong though!