Flutter Play Sound and Record Noise Levels - flutter

Can anybody help plz!
Ive been running into this issue for a while now. The app runs fine on an ios simulator aswell as android device but not on an ios device. The general idea is that i want a tone to play and once that tone starts playing i need to record the decibel levels that the device picks up. From what i understand, the ios device only allows for one channel to be used at a time, wheather it be input or output. I am using the audioplayers and noise_meter plugins. All permissions have been granted and if i run the one method alone it works and visa versa but when running both methods it throws this error.
https://pub.dev/packages/noise_meter
https://pub.dev/packages/audioplayers
The errors i am receiving are below:
"iOS => call startHeadlessService, playerId fa642ed8-2266-48b6-ac9f-1f474f225864"
"calling start headless service (\n 4430477584143042153\n)"
"iOS => call setReleaseMode, playerId fa642ed8-2266-48b6-ac9f-1f474f225864"
"iOS => call play, playerId fa642ed8-2266-48b6-ac9f-1f474f225864"
"setUrl /var/mobile/Containers/Data/Application/0E0D63C7-B1DD-4BD3-BC84-2AFB5C80B8D9/Library/Caches/2100.mp3"
[VERBOSE-2:FlutterObservatoryPublisher.mm(101)] Failed to register observatory port with mDNS with error -65555.
[VERBOSE-2:FlutterObservatoryPublisher.mm(103)] On iOS 14+, local network broadcast in apps need to be declared in the app's Info.plist. Debug and profile Flutter apps and modules host VM services on the local network to support debugging features such as hot reload and DevTools. To make your Flutter app or module attachable and debuggable, add a '_dartobservatory._tcp' value to the 'NSBonjourServices' key in your Info.plist for the Debug/Profile configurations. For more information, see https://flutter.dev/docs/development/add-to-app/ios/project-setup#local-network-privacy-permissions
""
"iOS -> updateDuration...1.541224"
"iOS -> invokechannel"
"iOS -> onSoundComplete..."
[avas] AVAudioSession_iOS.mm:1149 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
"Error inactivating audio session Error Domain=NSOSStatusErrorDomain Code=560030580 \"(null)\""
Ive put a simple application together to merely demonstrate my issue:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:audioplayers/audio_cache.dart';
import 'package:flutter/services.dart';
import 'package:noise_meter/noise_meter.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static AudioCache player = AudioCache();
bool _isRecording = false;
StreamSubscription<NoiseReading> _noiseSubscription;
NoiseMeter _noiseMeter;
playSound() async{
player.play("2100.mp3");
}
void start() async {
//_noiseSubscription = _noiseMeter.noiseStream.listen(onData);
try {
_noiseSubscription = _noiseMeter.noiseStream.listen(onData);
} catch (exception) {
print(exception);
}
}
void onData(NoiseReading noiseReading) {
this.setState(() {
if (!this._isRecording) {
this._isRecording = true;
}
});
/// Do someting with the noiseReading object
print(noiseReading.toString());
}
void onError(PlatformException e) {
print(e.toString());
_isRecording = false;
}
void stopRecorder() async {
try {
if (_noiseSubscription != null) {
_noiseSubscription.cancel();
_noiseSubscription = null;
}
this.setState(() {
this._isRecording = false;
});
} catch (err) {
print('stopRecorder error: $err');
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
//start();
_noiseMeter = new NoiseMeter(onError);
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// player.play("2100.mp3");
//
// player.clearCache();
playSound();
start();
},
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Any help will be much appreciated.

This seems to be a known error for iOS 14+ devices.
On iOS 14 and higher, enable the Dart multicast DNS service in the
Debug version of your app to add debugging functionalities such as
hot-reload and DevTools via flutter attach.
Check out the documentation about "Local Network Privacy Permissions". From there, I suggest to follow the instructions on enabling the Dart multicast DNS service in the Debug version of your app.

Related

java.lang.IllegalStateException: Reply already submitted -- Simple way to send multiple data from native to dart

I followed the docs to integerate a native libarary into flutter. https://docs.flutter.dev/development/platform-integration/platform-channels?tab=android-channel-java-tab.
Every things working when I use one method channel as in the mentioned docs. But as I Call result.success(); multiple times flutter is giving expection.
Native Code of Android.
package com.example.batterylevel;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "samples.flutter.dev/battery";
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
}
if(call.method.equals("getPluginData")){
String pluginData = getPluginData();
result.success(pluginData);
// if (batteryLevel != -1) {
//
// result.success(batteryLevel);
// } else {
// result.error("UNAVAILABLE", "Battery level not available.", null);
// }
}
//
else {
result.notImplemented();
}
}
);
}
private int getBatteryLevel() {
int batteryLevel = -1;
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
}
return batteryLevel;
}
private String getPluginData(){
return "This is the plugin Data";
}
}
Flutter Dart Code.
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const platform = MethodChannel('samples.flutter.dev/battery');
String _batteryLevel = 'Unknown battery level.';
String _pluginData = 'Unknow Plugin Data';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
Future<void> _getPluginData() async {
String pluginData;
try {
final String result = await platform.invokeMethod('getPluginData');
pluginData = 'Plugin Data at $result % .';
} on PlatformException catch (e) {
pluginData = "Failed to get Plugin Data: '${e.message}'.";
}
setState(() {
_pluginData = pluginData;
});
}
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
_getBatteryLevel();
_getPluginData();
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Text(_batteryLevel),
Text(_pluginData),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

Flutter: MissingPluginException when I call platform channel from spawned isolate using isolate_handler package

When I want to call a method channel from a spawned isolate using isolate_handler (because it doesn't work using dart's isolates), I get a MissingPluginException which doesn't happen when calling method channel from the main isolate.
class TestingIsolate {
static int _callCount = 0;
static int _lastNumber = 0;
final _isolates = IsolateHandler();
final resultStreamController = StreamController<double>();
static void _entryPoint(Map<String, dynamic> context) {
final messenger = HandledIsolate.initialize(context);
_startTesting(messenger);
}
Stream<double> init() {
_isolates.spawn<double>(_entryPoint,
onReceive: (result) => resultStreamController.add(result));
return resultStreamController.stream;
}
static const platform =
MethodChannel('com.mycompany.plugin_performance_test_poc');
static void _startTesting(HandledIsolateMessenger messenger) {
// Timer.periodic(const Duration(seconds: 1), (timer) {
// messenger.send(_callCount / timer.tick);
// });
final stopwatch = Stopwatch();
stopwatch.start();
while (stopwatch.elapsedMilliseconds < 3000) {
platform.invokeMethod('performanceTest', {'data': _lastNumber}).then(
(result) {
print("inside, $_lastNumber");
_lastNumber = result;
_callCount++;
});
}
stopwatch.stop();
messenger.send(_callCount * 3000 / stopwatch.elapsedMilliseconds);
}
}
I'm trying to test how many times can I run method channel per second.
Here's the UI part:
import 'package:async/async.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_performance_test_poc/testing_isolate.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double _counter = 0;
Future<void> _executeTest() async {
TestingIsolate().init().listen((result) {
setState(() {
_counter = result;
});
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'The plugin has been called this many times per second:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _executeTest,
tooltip: 'Increment',
child: const Icon(Icons.play_arrow),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
And A native part of the code for android:
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.mycompany.plugin_performance_test_poc"
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "performanceTest") {
if (call.hasArgument("data")) {
result.success(call.argument<Int>("data") as Int + 1)
}
} else {
result.notImplemented()
}
}
}
}

flutter desktop: cannot respond to lifecycle events?

flutter's app lifecycle management API works fine on mobile platforms, so I'm trying it on desktop, e.g., macOS.
But it seems that the same callback that works on the mobile platforms does not work on desktop.
Did I miss anything?
Code
Using the following hello-world code, I was minimizing/maximizing/quitting the app, under all these cases, the lifecycle callback: didChangeAppLifecycleState was never triggered. The same code was triggered fine on iOS simulator build.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
List<AppLifecycleState> _lifecycleStates;
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_lifecycleStates = [];
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
_lifecycleStates.add(state);
if (_lifecycleStates.length > 2) {
_lifecycleStates.removeAt(0);
}
final isAppBackgrounded =
(_lifecycleStates.first == AppLifecycleState.resumed &&
_lifecycleStates.last == AppLifecycleState.inactive) ||
(_lifecycleStates.first == AppLifecycleState.inactive &&
_lifecycleStates.last == AppLifecycleState.paused);
final isAppForegrounded =
(_lifecycleStates.first == AppLifecycleState.inactive ||
_lifecycleStates.first == AppLifecycleState.paused) &&
_lifecycleStates.last == AppLifecycleState.resumed;
if (isAppBackgrounded) {
// when app is paused,
// - receive data in comm but bypass sink
// - bypass meters
setState(() {
// add code
print('quitting');
});
}
if (isAppForegrounded) {
// when app is resumed,
// - receive data in comm and send to sink
// - resume meters
setState(() {
// add code
});
}
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

How to bring an app from background to foreground in flutter

I have an app that is managing audio calls. When a call is made to the add and the app is running in the background I need to bring the app in the foreground state. I tried to use Navigator. push but without any result.
You can use the package bringtoforeground. It's fairly in the early stages with respect to its version but it works.
iOS
But this only works on android, you have to keep in mind that iOS apps that are on the background are destroyed. you can read this do
see details here
Android
So this implementation will only work on Android.
The best thing with this package is that you can use it with Firebase Cloud Messaging (FCM) or any other for that matter.
This is their example, Bringtoforeground.bringAppToForeground(); this is the piece of code you use to bring your app to the foreground.
import 'dart:async';
import 'package:bringtoforeground/bringtoforeground.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
#override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
Timer.periodic(Duration(seconds: 10), (t) {
Bringtoforeground.bringAppToForeground(); //This is the only thing that matters
});
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
),
);
}
}
Install flutter_foreground_task package here is
and use FlutterForegroundTask.minimizeApp() for app to background
and use FlutterForegroundTask.launchApp() for app to foreground that's all.
I think it helps.
if you work with flutter_local_notifications package
you can add this argument to AndroidNotificationAction
from here
hope this help (:

Where do I run initialisation code when starting a flutter app?

Where do I run initialisation code when starting a flutter app?
void main() {
return runApp(MaterialApp(
title: "My Flutter App",
theme: new ThemeData(
primaryColor: globals.AFI_COLOUR_PINK,
backgroundColor: Colors.white),
home: RouteSplash(),
));
}
If I want to run some initialisation code to, say fetch shared preferences, or (in my case) initialise a package (and I need to pass in the the BuildContext of the MaterialApp widget), what is the correct way to do this?
Should I wrap the MaterialApp in a FutureBuilder? Or is there a more 'correct' way?
------- EDIT ---------------------------------------------------
I have now placed the initialisation code in RouteSplash() widget. But since I required the BuildContext of the app root for the initialisation, I called the initialisation in the Widget build override and passed in context.ancestorInheritedElementForWidgetOfExactType(MaterialApp). As I don't need to wait for initialisation to complete before showing the splash screen, I haven't used a Future
One simple way of doing this will be calling the RouteSplash as your splash screen and inside it perform the initialization code as shown.
class RouteSplash extends StatefulWidget {
#override
_RouteSplashState createState() => _RouteSplashState();
}
class _RouteSplashState extends State<RouteSplash> {
bool shouldProceed = false;
_fetchPrefs() async {
await Future.delayed(Duration(seconds: 1));// dummy code showing the wait period while getting the preferences
setState(() {
shouldProceed = true;//got the prefs; set to some value if needed
});
}
#override
void initState() {
super.initState();
_fetchPrefs();//running initialisation code; getting prefs etc.
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: shouldProceed
? RaisedButton(
onPressed: () {
//move to next screen and pass the prefs if you want
},
child: Text("Continue"),
)
: CircularProgressIndicator(),//show splash screen here instead of progress indicator
),
);
}
}
and inside the main()
void main() {
runApp(MaterialApp(
home: RouteSplash(),
));
}
Note: It is just one way of doing it. You could use a FutureBuilder if you want.
To run code at startup, put it in your main.dart. Personally, that's the way I do it, to initialise lists etc.