Skip to content

Enables background usage of flutter-blue #210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

rmawatson
Copy link

@rmawatson rmawatson commented Mar 9, 2019

Changed this PR to come from rmawatson:background_feature instead of rmawatson:master

Android:
Swaps activity() calls for context() where only a context is required. The only place an activity is required is when requesting permissions. This patch will return an error when the plugin is used where permissions have not been granted, and there is no activity available to request permissions

iOS:
To use bluetooth-central background role and continue to processes in the background it is required that a unique ID (CBCentralManagerOptionRestoreIdentifierKey) be set when the CBCentralManager is initialized. (https://developer.apple.com/documentation/corebluetooth/cbcentralmanageroptionrestoreidentifierkey?language=objc).

Delays instanciation of the cbcentralmanager to when it is first used, so allow setting of a unique id from dart.

When CBCentralManagerOptionRestoreIdentifierKey is set, the CBCentralManagerDelegate must implement centralManager:willRestoreState. The current implmentation is empty as it appears that setting a unique ID is sufficient to stop iOS killing the app once it has been backgrounded, if a bluetooth connection is active, or a scan is in progress.

This has a side effect of printing an API-MISUSE warning when CBCentralManagerOptionRestoreIdentifierKey is not used, because the method centralManager:willRestoreState is always implemented. The warning is harmless when not using CBCentralManagerOptionRestoreIdentifierKey.

Dart:

To support the setting of a unique Id, introduces setUniqueId(String). This should be called before any methods that will instanciate the native instance of the cbcentralmanager.

Additional Notes:

iOS:

Even when a unique ID is set, the app could still theoretically be killed for other reasons by iOS (although I have not experienced this).

If the app is killed by iOS at any point and bluetooth-tasks are ongoing, iOS will restart the app and willRestoreState method will be called on the CBCentralManagerDelegate. It allows about 10 seconds to handle the event, before the app is killed again. It may be nice to allow registering a handler in flutter that can be called to handle such events. This would be iOS only.

States that can be saved and restored:

https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/central_manager_state_restoration_options?language=objc

Additionally it would be good to be able to pass through the application restart reason. Currently flutter has no way of knowing why it was started and main() will run if it was started to handle something through willRestoreState. If it was started to handle this callback, the ideal would be run this in a standalone isolate, passing the various restored states to the handler, but allow the main to exit without attempting to run any code by checking the start reason.

Android:
Swaps activity() calls for context() where only a context is required. The only place an activity is required is when requesting permissions. This patch will return an error when the plugin is used where permissions have not been granted, and there is no activity available to request permissions

iOS:
To use bluetooth-central background role and continue to processes in the background it is required that a unique ID (CBCentralManagerOptionRestoreIdentifierKey) be set when the CBCentralManager is initialized. (https://developer.apple.com/documentation/corebluetooth/cbcentralmanageroptionrestoreidentifierkey?language=objc).

Delays instanciation of the cbcentralmanager to when it is first used, so allow setting of a unique id from dart.

When CBCentralManagerOptionRestoreIdentifierKey is set, the CBCentralManagerDelegate must implement centralManager:willRestoreState. The current implmentation is empty as it appears that setting a unique ID is sufficient to stop iOS killing the app once it has been backgrounded, if a bluetooth connection is active, or a scan is in progress.

This has a side effect of printing an API-MISUSE warning when CBCentralManagerOptionRestoreIdentifierKey is not used, because the method centralManager:willRestoreState is always implemented. The warning is harmless when not using CBCentralManagerOptionRestoreIdentifierKey.

Dart:

To support the setting of a unique Id, introduces setUniqueId(String). This should be called before any methods that will instanciate the native instance of the cbcentralmanager.
@treyerl
Copy link

treyerl commented Apr 11, 2019

@rmawatson Thank you for your work on this. There is no way to pass through the application restart reason. But it is possible to run flutter in headless mode an call it with a different entry point - as I read from geofencing service examples: Flutter's reference example for background processes [_headlessRunner runWithEntrypointAndLibraryUri:entrypoint libraryUri:uri];, or here, Flutter Engine Reference

Probably (didn't check in detail) the headless runner would be a good candidate for your empty willRestoreState method.

@rmawatson
Copy link
Author

rmawatson commented Apr 21, 2019

@treyerl Thanks for that info about the restart reason. I think it should be possible to make the restart reason available from iOS so in the flutter main() entry point you can just branch on the startup reason and gracefully exit when its handled the event.

Although I never actually got round to trying this with flutter blue (as I didn't need it) something like this https://github.com/rmawatson/flutter_startup for getting the startup type, then just providing a way to get the info passed into the startup reason callback should be enough... all gets a bit messy and platform specific though.

@patrickdronk
Copy link

Is there any holdups in this? I'd really like to use it!

@alod2019
Copy link

The same question - any update on when this fix is supposed to be released ?

@josh-burton
Copy link

Can we get this merged?

@MichealReed
Copy link

@pauldemarco is this on the roadmap to be merged? Lots of people needing this functionality.

@MichealReed
Copy link

MichealReed commented Aug 5, 2019

@rmawatson I tried to merge your branch with the latest from master, but it seems this commit introduces a new issue.

My fork:
https://github.com/MichealReed/flutter_blue/tree/background_feature

Commit with issue:
0879f5f#diff-2d2a8584d0b1a81f07c64ac07f23ee36

Trace:
image

Any suggestions?

Edit: I can remove the activity.runOnUiThread() wrapper, but then it breaks @pauldemarco's example app. Seems to eliminate the crash for my purpose though.

Edit2: posted an issue update here (rmawatson/flutter_isolate#19) if anyone can help solve this is the only thing outstanding for flutter_blue working in the background with an isolate.

@edsonboldrini
Copy link

Hi guys, I'm needing a background service that runs every 15 minutes periodically that connect with a nearby smartband, fetch its data and send this data to a server without any user interaction. Could someone help me about how should I build this?

@jasonwong2065
Copy link

Hi guys, any updates on this? This would be such a useful feature. Thank you for all your work! 👍

@edsonboldrini
Copy link

Hi guys, any updates on this? This would be such a useful feature. Thank you for all your work!

I stop waiting for this and started to use a new lib called by rx_ble, and for my needs, everything is working fine, here is the link

@MichealReed
Copy link

@edsonboldrini are you using this with an isolate in the background?

@edsonboldrini
Copy link

@edsonboldrini are you using this with an isolate in the background?

I'm using this with flutter_workmanager plugin, and it is working fine.

@boskokg
Copy link

boskokg commented Mar 15, 2020

Note:
I added your code together with other merge request.

flutter_blue:
git:
url: https://github.com/boskokg/flutter_blue.git
ref: 0.7.1

@xurei
Copy link

xurei commented Apr 15, 2020

@boskokg Shouldn't we close this PR then ?

@boskokg
Copy link

boskokg commented Apr 15, 2020

@xurei I tested setting uniqueId in the production but I did not see any improvements described in this this PR (related to iOS). Other things are already on the latest release of this plugin, so I am not using my branch anymore...

@eduardoh89
Copy link

Note:
I added your code together with other merge request.

flutter_blue:
git:
url: https://github.com/boskokg/flutter_blue.git
ref: 0.7.1

it is possible with this modification execute the plugin in a headless task?

@JuniorJPDJ
Copy link

JuniorJPDJ commented Jan 16, 2021

Any update here or in #191?
Maybe you could rebase it on top of latest master?

alexanderbelokon-mway added a commit to alexanderbelokon-mway/flutter_blue that referenced this pull request Jan 18, 2021
@Cbosh
Copy link

Cbosh commented Jul 29, 2022

The iOS app is still getting killed when running in the background. How do you create Bluetooth object again on start up to reconnect to Bluetooth because scanning is not working in the background.

@edsonboldrini, the plugin that you using is it working on restoring BLE connection when the app is killed in iOS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.