skip to Main Content

My app is connected to BLE accessory using CoreBluetooth state restoration and preservation (SRP). This means that the native part of the app can receive HR samples continuously even when the app is in the background. However, what I can also see is that the Flutter part of the app keeps running despite app being in paused lifecycle state.

I did a simple experiment and started timer in Flutter when using and not using Core Bluetooth SRP.

  • when not using the SRP the Timer stopped printing into log after 20 seconds
  • when using SRP the Timer kept running indefinitely as long as the BLE accessory was sending HR samples

What I’m looking for is to maintain the typical Flutter behavior but keep using SRP on the native side.

  1. Which part of the Flutter is responsible for stopping the "execution" when app goes to paused state?
  2. Can Flutter be paused despite SRP being on?
  3. Is there a way to put Flutter engine to paused state programmatically?
  4. If not, do you see any other ways to keep the typical Flutter engine/ViewController behavior?

2

Answers


  1. The issue here is in some sort of misunderstanding. When the flutter part is paused, it doesn’t mean it pauses its execution by default. You have to manually pause all the needed stuff when you go to this state.

    For the most "functional(non ui)" cases, those states WidgetsBindingObserver catches are mere ‘indications’ rather than ‘actions’… This is especially applicable when you listen to something native part emitting in the background.

    Here is some explanation from the official documentation:

    paused → const AppLifecycleState

    The application is not currently visible to the user and is not responding to user input.

    When the application is in this state, the engine will not call the PlatformDispatcher.onBeginFrame and PlatformDispatcher.onDrawFrame callbacks.

    This state is only entered on iOS and Android.>

    It means that the Flutter engine only skips drawing stuff on screen – all the other operations are active and will be active till the app’s death. In the case of iOS, it may never happen till the explicit kill of the app. In Android, the OS can kill it in arbitrary time or not kill it – depending on the load of the OS itself.

    To ignore any activity during the paused state, you have to explicitly and manually unsubscribe any listeners in the ‘paused’ state and subscribe them once more in the resumed state. I am saying words like ‘subscribe’ and ‘unsubscribe’ one because I don’t know the specifics of your code – you may easily just ignore all the events or something…

    If you want the flutter part not to function at all when the app is in the background, you have to kill the flutter part manually – you can do it if you established your flutter engine connection manually, not relying on FluttFlutterViewController, FlutterFragment etc. You have to have control over the code in order to do that. Afterward, when your app is in the foreground once more(to know that you would have to rely on native callbacks since when the flutter engine is dead, there is no callback in dart code), you will be able to reestablish flutter infrastructure and run it once more.

    I don’t recommend the latter approach since it is sooo redundant – ignoring events and/or subscribing/unsubscribing is sufficient in most cases. I think even including yours.

    Hope it helps.

    Login or Signup to reply.
  2. Flutter’s behavior in the background, especially when integrated with native modules, can sometimes lead to non-standard behaviors. Here are answers to your specific questions and suggestions to help you:

    1.Which part of Flutter is responsible for stopping the "execution" when the app goes to the paused state?

    Flutter’s AppLifecycleState manages the different lifecycle states of a Flutter app. Normally, when an app goes to the background, it goes into the paused state, which should halt most of Flutter’s activities. This is managed at the engine level.

    2.Can Flutter be paused despite SRP being on?

    When using state restoration and preservation with CoreBluetooth, the native part of your app will remain active even in the background. However, Flutter should be unaware of this background activity unless explicitly communicated via platform channels. Flutter’s engine should still pause as usual unless something in your integration is causing it to remain active.

    3.Is there a way to put the Flutter engine to a paused state programmatically?

    Not directly from the Dart side. The Flutter engine will respond to iOS lifecycle events (like UIApplicationDidEnterBackgroundNotification), but you can’t force the Flutter engine into a paused state from Dart.

    4.If not, do you see any other ways to keep the typical Flutter engine/ViewController behavior?

    Here are some suggestions:

    Explicitly Pause Activities: Before your app goes into the background, you can use Flutter’s WidgetsBindingObserver to listen for lifecycle events and pause any timers or activities you’ve started in Flutter.

      class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
      }
    
      @override
      void dispose() {
        WidgetsBinding.instance.removeObserver(this);
        super.dispose();
      }
    
      @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        if (state == AppLifecycleState.paused) {
          // Pause your timers or other activities here
        }
      }
    }
    

    Platform Channels: Use platform channels to communicate between the native and Flutter sides of your app. If the native side is aware that it’s going into a background mode where Flutter should not be active, send a message to the Dart side to pause any activities.

    Check Integrations: Ensure that your integration of CoreBluetooth or any other native modules isn’t unintentionally keeping the Flutter engine awake. For instance, if you’re continuously sending data from the native side to Flutter via platform channels, it could keep the Flutter engine active.

    Reconsider Architecture: If possible, consider restructuring such that Flutter doesn’t need to be aware of the background BLE activities. Collect the data on the native side and sync it with Flutter when the app comes to the foreground.

    While you can’t directly force the Flutter engine into a paused state, you can manage your app’s activities based on lifecycle states and ensure that background activities don’t unintentionally keep Flutter awake.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search