Whirlwind Whirlwind - 12 days ago 8
iOS Question

Core Bluetooth - Performing Long-Term Actions in the Background

This is from the Core Bluetooth Background Processing for iOS Apps section found in official docs:

Performing Long-Term Actions in the Background


Some apps may need to use the Core Bluetooth framework to perform
long-term actions in the background. As an example, imagine you are
developing a home security app for an iOS device that communicates
with a door lock (equipped with Bluetooth low energy technology). The
app and the lock interact to automatically lock the door when the user
leaves home and unlock the door when the user returns—all while the
app is in the background. When the user leaves home, the iOS device
may eventually become out of range of the lock, causing the connection
to the lock to be lost. At this point, the app can simply call the
connectPeripheral:options: method of the CBCentralManager class, and
because connection requests do not time out, the iOS device will
reconnect when the user returns home.


Okay, we have an app which locks/unlocks doors as appropriate... So as pointed out, this works when app is in the background (most likely in the suspended mode). Now, lets move on (with quoting docs):


Now imagine that the user is away from home for a few days. If the app
is terminated by the system while the user is away, the app will not
be able to reconnect to the lock when the user returns home, and the
user may not be able to unlock the door. For apps like these, it is
critical to be able to continue using Core Bluetooth to perform
long-term actions, such as monitoring active and pending connections.


So, if the user was away from home for a few days, and app has been terminated by the iOS, we will have to implement state preservation and restoration, so that iOS relaunch the app when connection request is detected, and let the app to unlock the door. Related quotes:


In the case of the home security app described above, the system
would monitor the connection request, and re-relaunch the app to
handle the centralManager:didConnectPeripheral: delegate callback when
the user returned home and the connection request completed.


This all make sense, but pay attention to this part again:


Now imagine that the user is away from home for a few days. If the app
is terminated by the system while the user is away, the app will not be able to reconnect to the lock when the user returns home, and
the user may not be able to unlock the door. For apps like these, it
is critical to be able to continue using Core Bluetooth to perform
long-term actions...


Does this means, if the app is forcefully killed by the user at some moment while he was away from home, that this will work as well ? Means when user comes home, the door will unlock anyway, or he must manually relaunch the app to unlock the door?

I am asking this, because of how relaunch of terminated apps works. It is not the same when user kills the app, and when iOS kills the app which supports background execution:


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...


Source

So once again, if the user was away for a few days and he has closed the app by double tapping Home button and dragging up, will he be able to enter his home without manually relaunching the app?

Answer

No. If the app is forcefully killed by the user then it will not be woken up again. The only scenario where it will be woken up is if the app was terminated by iOS itself, which will happen sooner or later when the app has not been it the foreground for a while. It will also not be relaunched if the device is rebooted.

Having said that, from my experience with Core Bluetooth I have come to the conclusion that State Preservation is way too unreliable. I would believe that the use-case that you are trying to implement will not work well enough, which is ironic since it is exactly the use-case that Apple is promoting it their documentation.

For example, you will have issues with the following:

State restoration will only relaunch your app due to bluetooth related activity if the event originates from a peripheral accessory that you are communicating with, such as connect/disconnect events and characteristics notifications. For other events, most importantly general bluetooth-state-change events, your app will not be relaunched and notified of this. The reason why this is so bad is because any bluetooth-state-change events will cause all pending connections to be tossed, meaning that your pending connections to the door lock will be lost. However, since your app is not relaunched to be notified of this, then it effectively means that your application will still believe that the connections are still pending when in fact they are not. Since your application is terminated at this time, the only way for it to wake up again is by having the user manually launch it again (or alternatively “hack” other background modes for this purpose, which will NOT work very reliably either).

This scenario happens if the user toggles Flight Mode, toggles Bluetooth, power cycles the iOS device, or any other undefined reasons that many cause state changes… And it is very unlikely that a bluetooth-state-change will not happen if "... the user is away from home for a few days.".

This "issue" has been reported by me and others multiple times, but Apple does not appear to want to fix it for some reason.

Apart from this, many other issues exists as well, such as the XPC connection being interrupted at different times for no apparent reason. I have also noticed that the pending connection can go into “limbo” mode where the peripheral state gets set to Connecting, but in fact it will never connect unless you cycle the connection state. Etc, etc, ...

/A