How do I run code in the background, even with the screen off in Flutter?

Share This Post

Hello Guys, Are You Looking For run code in the background, even with the screen off in Flutter ? Youre At Right Place. Our Team Is Posting Here Possible All Solution for run code in the background, even with the screen off, If You Satisfy with Our Article Please Comment Below Or Any Help Please Comment Below.

Solution 1:

Answering the question of how to implement your specific timer case doesn’t actually have to do with background code. Overall running code in the background is something discouraged on mobile operating systems.

For example, iOS Documentation discusses background code in greater detail here:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

Instead mobile operating systems provide apis (like a timer/alarm/notification apis) to call back to your application after a specific time. For example on iOS you can request that your application be notified/woken at a specific point in the future via UINotificationRequest:
https://developer.apple.com/reference/usernotifications/unnotificationrequest
This allows them to kill/suspend your app to achieve better power savings and instead have a single highly-efficent shared system service for tracking these notifications/alarms/geofencing, etc.

Flutter does not currently provide any wrappers around these OS services out-of-the-box, however it is straighforward to write your own using our platform-services model:
flutter.io/platform-services

We’re working on a system for publishing/sharing service integrations like this so that once one person writes this integration (for say scheduling some future execution of your app) everyone can benefit.

Separately, the more general question of “is it possible to run background Dart code” (without having a FlutterView active on screen), is “not yet”. We have a bug on file:
https://github.com/flutter/flutter/issues/3671

The use-case driving that kind of back-ground code execution is when your app receives a notification, wants to process it using some Dart code without bringing your app to the front. If you have other use cases for background code you’d like us to know about, comments are most welcome on that bug!

Solution 2:

Short answer: no, it’s not possible, although I have observed a different behavior for the display going to sleep. The following code will help you understand the different states of a Flutter app on Android, tested with the these Flutter and Flutter Engine versions:

  • Framework revision b339c71523 (6 hours ago), 2017-02-04 00:51:32
  • Engine revision cd34b0ef39

Create a new Flutter app, and replace the content of lib/main.dart with this code:

import 'dart:async';

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class LifecycleWatcher extends StatefulWidget {
  @override
  _LifecycleWatcherState createState() => new _LifecycleWatcherState();
}

class _LifecycleWatcherState extends State<LifecycleWatcher>
    with WidgetsBindingObserver {
  AppLifecycleState _lastLifecyleState;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void onDeactivate() {
    super.deactivate();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print("LifecycleWatcherState#didChangeAppLifecycleState state=${state.toString()}");
    setState(() {
      _lastLifecyleState = state;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_lastLifecyleState == null)
      return new Text('This widget has not observed any lifecycle changes.');
    return new Text(
        'The most recent lifecycle state this widget observed was: $_lastLifecyleState.');
  }
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter App Lifecycle'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _timerCounter = 0;
  // ignore: unused_field only created once
  Timer _timer;

  _MyHomePageState() {
    print("_MyHomePageState#constructor, creating new Timer.periodic");
    _timer = new Timer.periodic(
        new Duration(milliseconds: 3000), _incrementTimerCounter);
  }

  void _incrementTimerCounter(Timer t) {
    print("_timerCounter is $_timerCounter");
    setState(() {
      _timerCounter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(config.title),
      ),
      body: new Block(
        children: [
          new Text(
            'Timer called $_timerCounter time${ _timerCounter == 1 ? '' : 's' }.',
          ),
          new LifecycleWatcher(),
        ],
      ),
    );
  }
}

When launching the app, the value of _timerCounter is incremented every 3s. A text field below the counter will show any AppLifecycleState changes for the Flutter app, you will see corresponding output in the Flutter debug log, e.g.:

[[email protected]:~/flutter/helloworld]$ flutter run
Launching lib/main.dart on SM N920S in debug mode...
Building APK in debug mode (android-arm)...         6440ms
Installing build/app.apk...                         6496ms
I/flutter (28196): _MyHomePageState#constructor, creating new Timer.periodic
Syncing files to device...
I/flutter (28196): _timerCounter is 0

?  To hot reload your app on the fly, press "r" or F5. To restart the app entirely, press "R".
The Observatory debugger and profiler is available at: http://127.0.0.1:8108/
For a more detailed help message, press "h" or F1. To quit, press "q", F10, or Ctrl-C.
I/flutter (28196): _timerCounter is 1
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused
I/flutter (28196): _timerCounter is 2
I/flutter (28196): _timerCounter is 3
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.resumed
I/flutter (28196): _timerCounter is 4
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused
I/flutter (28196): _timerCounter is 5
I/flutter (28196): _timerCounter is 6
I/flutter (28196): _timerCounter is 7
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.resumed
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused
I/flutter (28196): _timerCounter is 8
I/flutter (28196): _MyHomePageState#constructor, creating new Timer.periodic
I/flutter (28196): _timerCounter is 0
I/flutter (28196): _timerCounter is 1

For the above log output, here are the steps I did:

  1. Launch app with flutter run
  2. Switch to other app (_timerCounter value 1)
  3. Return to Flutter app (_timerCounter value 3)
  4. Pressed power button, display turned off (_timerCounter value 4)
  5. Unlocked phone, Flutter app resumed (_timerCounter value 7)
  6. Pressed back button on phone (_timerCounter value not changed). This is the moment where the FlutterActivity gets destroyed and the Dart VM Isolate as well.
  7. Flutter app resumed (_timerCounter value is 0 again)

Switching between apps, pressing power or back button
When switching to another app, or when pressing the power button to turn of the screen the timer continues to run. But when pressing the back button while the Flutter app has the focus, the Activity gets destroyed, and with it the Dart isolate. You can test that by connecting to the Dart Observatory when switching between apps, or turning of the screen. The Observatory will show an active Flutter app Isolate running. But when pressing the back button, the Observatory shows no running Isolate. The behavior was confirmed on a Galaxy Note 5 running Android 6.x, and a Nexus 4 running Android 4.4.x.

Flutter app lifecycle and Android lifecycle
For the Flutter widget layer, only the paused and resumed states are exposed. Destroy is handled by Android Activity for an Android Flutter app:

/**
 * @see android.app.Activity#onDestroy()
 */
@Override
protected void onDestroy() {
    if (flutterView != null) {
        flutterView.destroy();
    }
    super.onDestroy();
}

Since the Dart VM for a Flutter app is running inside the Activity, the VM will be stopped every time the Activity gets destroyed.

Flutter Engine code logic
This doesn’t directly answer your question, but will give you some more detailed background info on how the Flutter engine handles state changes for Android.
Looking through the Flutter engine code it becomes obvious that the animation loop is paused when the FlutterActivity receives the Android Activity#onPause event. When the application goes into paused state, according to the source comment here the following happens:

“The application is not currently visible to the user. When the application is in this state, the engine will not call the [onBeginFrame] callback.”

Based on my testing the timer continues to work even with the UI rendering being paused, which makes sense. It would be good to send an event into the widget layer using the WidgetsBindingObserver when the Activity gets destroyed, so developers can make sure to store the state of the Flutter app until the Activity is resumed.

Solution 3:

You can use the android_alarm_manager flutter plugin which lets you run Dart code in the background when an alarm fires.

Another way with more control would be to write a native Android service (using Java or Kotlin) for your app that communicates with the flutter frontend via device storage or shared prefs.

Solution 4:

You could use the flutter_workmanager plugin.
It’s better than the above mentioned AlarmManager since this is not recommended any more for Android.
The plugin also always for iOS background execution

This plugin allows you do register some background work and get a callback in Dart when it happened so you can perform a custom action.

void callbackDispatcher() {
  Workmanager.executeTask((backgroundTask) {
    switch(backgroundTask) {
      case Workmanager.iOSBackgroundTask:
      case "firebaseTask":
        print("You are now in a background Isolate");
        print("Do some work with Firebase");
        Firebase.doSomethingHere();
        break;
    }
    return Future.value(true);
  });
}

void main() {
  Workmanager.initialize(callbackDispatcher);
  Workmanager.registerPeriodicTask(
    "1",
    "firebaseTask",
    frequency: Duration(days: 1),
    constraints: WorkManagerConstraintConfig(networkType: NetworkType.connected),
  );
  runApp(MyApp());
}

I Hope This Article Is Help You. Comment Below Your Thought Here. Thank You.

Leave a Reply

Your email address will not be published. Required fields are marked *

close