flutter_blue icon indicating copy to clipboard operation
flutter_blue copied to clipboard

Enables background usage of flutter-blue

Open rmawatson opened this issue 5 years ago • 18 comments

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.

rmawatson avatar Mar 09 '19 15:03 rmawatson

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

treyerl avatar Apr 11 '19 09:04 treyerl

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

rmawatson avatar Apr 21 '19 23:04 rmawatson

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

patrickdronk avatar Jun 04 '19 12:06 patrickdronk

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

alod2019 avatar Jul 11 '19 08:07 alod2019

Can we get this merged?

josh-burton avatar Jul 18 '19 08:07 josh-burton

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

MichealReed avatar Aug 05 '19 13:08 MichealReed

@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: https://github.com/pauldemarco/flutter_blue/commit/0879f5f26e1f2afced197bab22e0bcb615e7eed1#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 (https://github.com/rmawatson/flutter_isolate/issues/19) if anyone can help solve this is the only thing outstanding for flutter_blue working in the background with an isolate.

MichealReed avatar Aug 05 '19 18:08 MichealReed

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?

edsonboldrini avatar Sep 11 '19 15:09 edsonboldrini

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

jasonwong2065 avatar Oct 06 '19 06:10 jasonwong2065

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

edsonboldrini avatar Oct 06 '19 19:10 edsonboldrini

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

MichealReed avatar Oct 09 '19 18:10 MichealReed

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

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

edsonboldrini avatar Oct 10 '19 00:10 edsonboldrini

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

boskokg avatar Mar 15 '20 05:03 boskokg

@boskokg Shouldn't we close this PR then ?

xurei avatar Apr 15 '20 17:04 xurei

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

boskokg avatar Apr 15 '20 21:04 boskokg

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?

eduardoh89 avatar May 18 '20 05:05 eduardoh89

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

JuniorJPDJ avatar Jan 16 '21 00:01 JuniorJPDJ

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

Cbosh avatar Jul 29 '22 12:07 Cbosh