Bluetooth still active after app killed using react native - react-native

I have a problem with the lifecycle of Bluetooth on iOS.
We are using React Native and the following library (https://github.com/innoveit/react-native-ble-manager) to manage our Bluetooth devices.
The devices sends data and clears its local data when it has sent all its data through bluetooth (we are only using ble messages ACK, no internal app ACK).
The problem is, that iOS seems to maintain the ble open when the app is killed, which is making the device think that it is still sending data that is processed correctly by our app, and clears it at the end (which causes data loss).
Is this a normal behaviour on iOS ? (the fact that the ble stays open for some time after the app is killed, and no errors are sent through ble ?)
Is there a way to force close the ble when the app is killed ?
Thanks

Is this a normal behaviour on iOS ? (the fact that the ble stays open for some time after the app is killed, and no errors are sent through ble ?)
Yes, this is normal. The OS holds open the connection and shares it with apps. The apps do not hold connections directly. It can take some time (generally on the order of seconds, but sometimes a bit longer) for the OS to drop the connection after the last app releases it.
Is there a way to force close the ble when the app is killed ?
No. There is no way to do anything when the app is killed (by which I assume you for force-quit, for example by swiping up on the app switcher).
All that said, I'm a bit surprised here that you're getting a write response back to the device if the app is no longer reading. When you say "ble messages ACK," specifically which "ack" do you mean? Are you getting a Write Response packet back? Or do you mean a lower-level ack?

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.

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!