polarofficial / polar-ble-sdk

Repository includes SDK and code examples. More info https://polar.com/en/developers
Other
475 stars 153 forks source link

[iOS] Core Bluetooth - Opt In to State Preservation and Restoration #293

Closed korzonkiee closed 11 months ago

korzonkiee commented 2 years ago

Platform your question concerns:

Device:

Description:

I'm going through the Core Bluetooth Background Processing for iOS Apps documentation and I'm trying to wrap my head around how to use iOS Polar SDK for continuous communication with a polar device. I'm gonna start with a graph showing the iOS app lifecycle to ensure common nomenclature. The graph has been copied from this repository.

                        +------------+
                        | Foreground |
                        +---+----^---+
                            |    |
           User changed app |    | User went back
                            |    |
                        +---v----+---+
                        | Background |
                        +-------+----+
                                |
                                |
                                |
            +-----+-----+       |
            | Suspended <-------+
            +-----+-----+  Run out of
                  |        computing time
                  |
Lack of resources |
                  |
             +----v---+
             | Killed +
             +--------+

By default, when using the iOS Core Bluetooth framework (on which Polar is based), the app is unable to perform Bluetooth-related tasks, nor is it aware of any Bluetooth-related events until it resumes to the foreground. In other words, the app can not communicate with BLE devices when the app is background (e.g. the app is minimized, not even killed).

In order to allow BT communication in the background, developers need to specify the Core Bluetooth background execution mode by adding the UIBackgroundModes key with bluetooth-central value to the Info.plist file. This is well documented in the Polar SDK docs.

This allows the Code Bluetooth framework to operate when the app is minimized. However, at any point in time, the operating system may decide to put the app into Suspended and then Killed state, for instance, when other, more important apps need resources.

There is a way to restore BT state and relaunch the app (to the background, i.e. silently), by using the "Core Bluetooth State Preservation and Restoration" mechanism described in detail here. Upon peripheral discovery, peripheral connection, and notifications/indications from a characteristic that the app has subscribed to, the OS will bring the app back to the background state to process the data. See the diagram below.

                        +------------+
                        | Foreground |
                        +---+----^---+
                            |    |
           User changed app |    | User went back
                            |    |
                        +---v----+---+
                  +---->+ Background <------+
      BLE event   |             |           |
                  |             |           |
                  |             |           |
            +-----+-----+       |           |
            | Suspended <-------+           |
            +-----+-----+  Run out of       | BLE event
                  |        computing time   |
                  |                         |
Lack of resources |                         |
                  |                         |
             +----v---+                     |
             | Killed +---------------------+
             +--------+

The "State Preservation and Restoration" mechanism has some limitiations, as it won't relaunch the app when:

  1. the app has been closed by the user (by swiping the app from the app manager view),
  2. the BT power button has been toggled in OS settings.

In other words, it will relaunch the app when:

  1. the app has been removed from memory by OS,
  2. the app has crashed,
  3. the airplane mode has been toggled (only if Bluetooth power is not toggled with Airplane Mode),
  4. the device has been restarted.

This topic is described more in-depth in this official documentation.

Regardless of the limitations, it seems that the iOS Polar SDK doesn't implement that mechanism (or at least I could find it in the source code). I skimmed through the CBDeviceListenerImpl.swift file that is responsible for instantiating the CBCentralManager. For "State Preservation and Restoration" mechanism to work, the key thing is to pass the CBCentralManagerRestoredStatePeripheralsKey when initializing the CBCentralManager, but that's not the case in Polar. It requires some other crucial steps that are described in detail here under the "Opt-In to State Preservation and Restoration" section.

Was there any particular reason for not incorporating that feature into the Polar iOS SDK?

JOikarinen commented 2 years ago

@korzonkiee thank you for very good description and lifting up this topic. Yes the "State Preservation and Restoration" handling is missing from Polar BLE SDK. With quick thinking there should be no obstacles in Polar BLE SDK which prevents implementation of "State Preservation and Restoration". This is definitely a topic which need to be taken into investigation and implementation -> l'll prioritise this high and try to come back as soon as possible.

korzonkiee commented 2 years ago

Hey @JOikarinen! I hope you are doing well.

I started playing around with the "State Preservation and Restoration" mechanism implementation here #298 as it's important for our team to have it as soon as possible.

With those changes added, my app is being revived from the suspended state — the system calls the AppDelegate.didFinishLaunchingWithOptions method and the Polar SDK correctly restores its state.

Could you, or someone from the team, take a look at the PR and let me know if there is anything that could be improved? I'd be really grateful 😊

JOikarinen commented 2 years ago

Hi @korzonkiee, thanks a lot for your effort.👍 I haven't forget this issue. I will proceed with this, if not today tomorrow latest.

JOikarinen commented 2 years ago

Update on this issue, I did early investigations on this. I need to continue tomorrow. I am slightly afraid to recover of BLE SDK to correct state after app is relaunched is maybe a bit more complex than initially thought, let's see.

JOikarinen commented 2 years ago

I have worked on this, but I need more time. It is a bit of challenging to recover SDK back to same status it was before termination.

JOikarinen commented 2 years ago

@korzonkiee there is now PR https://github.com/polarofficial/polar-ble-sdk/pull/299 where the State Preservation and Restoration functionality is implemented.

The implementation shall work for already existing connections, which are now restored if the app is terminated by the OS. If it is possible, please have a try and let me know whether the implementation satisfies your needs.

korzonkiee commented 2 years ago

Thanks you @JOikarinen. Really appreciate it. I'll give it a try today (or tomorrow latest) and will let you know!

korzonkiee commented 2 years ago

Hey @JOikarinen! Sorry for late response — I did give it a try and for now everything works as expected.

JOikarinen commented 1 year ago

Unfortunately the Bluetooth state Preservation and Restoration is not working as expected. The problem is, when the application is terminated and then booted back up, the SDK is not properly initialising itself in correct state where it was before termination. The consequence is that SDK won't work properly after termination.

The Bluetooth State Preservation and Restoration will be reverted in release 5.0.0. And is now already reverted in release 5.0.0-beta2

orestesgaolin commented 11 months ago

hey there, was wondering what does it mean it was "completed"? Is state preservation coming in next release?

samulimaa commented 11 months ago

Hey, there is no near future plans to reintroduce State Preservation and Restoration as this is not functioning as expected.