Use background service only in minimized state - flutter

I want to use this background service only whenever my app is in minimized state. Is there way to do this? I've tried changing isForegroundMode to false, but when app is running for some reason it still keeps printing the value. I don't want this to work when the app is opened, only when user minimizes it. Is this doable? Im using this package: https://pub.dev/packages/flutter_background_service
void onIosBackground() {
WidgetsFlutterBinding.ensureInitialized();
}
void onStart() {
WidgetsFlutterBinding.ensureInitialized();
final service = FlutterBackgroundService();
Timer.periodic(const Duration(seconds: 3), (timer) async {
if (!(await service.isServiceRunning())) timer.cancel();
service.setNotificationInfo(
title: "My App Service",
content: "Updated at ${DateTime.now()}",
);
print("Test");
});
}
Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: false,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: onIosBackground,
),
);
}

Related

flutter, flutter_background_service stopSelf() on notification action press doesn't work

I want to stop service on "shutdown" notification action press, everything else works but service don't stop on service.stopSelf().
notification :
simpleNotification(
{required int minutes,
required int seconds,
required FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin}) {
flutterLocalNotificationsPlugin.show(
1,
'App sync running ....',
'Interval $minutes:$seconds',
const NotificationDetails(
android: AndroidNotificationDetails(
"1",
'MY FOREGROUND SERVICE',
subText: "App Sync is running .....",
icon: 'ic_bg_service_small',
ongoing: false,
playSound: false,
enableVibration: false,
tag: 'simple_notification',
actions: [
AndroidNotificationAction("pause", "pause"),
AndroidNotificationAction("shutdown", "shutdown"),
],
),
),
);
}
I'm initializing service like this
Future<void> initializeService() async {
final service = FlutterBackgroundService();
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// <---------------------Notification-------------------------->
const AndroidNotificationChannel channel = AndroidNotificationChannel(
"1",
'MY FOREGROUND SERVICE',
description: 'This channel description',
importance: Importance.high,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
android: AndroidInitializationSettings("#mipmap/ic_launcher"),
),
onDidReceiveBackgroundNotificationResponse: onNotificationResponse,
);
// <---------------------Notification-------------------------->
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
notificationChannelId: "1",
initialNotificationTitle: 'AWESOME SERVICE',
initialNotificationContent: 'Initializing',
foregroundServiceNotificationId: 1,
),
iosConfiguration: IosConfiguration(),
);
}
In above code onDidReceiveBackgroundNotificationResponse accepts onNotificationResponse top level function. on 'shutdown' press print("shutdown pressed ....") executes but service.invoke doesn't.
similarly on "pause" action press print("pause action pressed..."); executes as expected.
#pragma('vm:entry-point')
void onNotificationResponse(NotificationResponse notificationResponse) {
if (notificationResponse.actionId == "pause") {
print("pause action pressed...");
}
if (notificationResponse.actionId == "shutdown") {
// <---------this doesn't work----------->
final service = FlutterBackgroundService();
service.invoke("stopService");
print("Shutdown pressed...");
}
}
In one of my widget service.invoke works perfectly, which is similar to the previous conditional statement block in onNotificationResponse function where I'm checking for shutdown action press, which doesn't work.
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(Colors.pink),
),
onPressed: () async {
final service = FlutterBackgroundService();
service.invoke("stopService");
print("service Stopped...");
},
child: const Text(" Stop service "),
)
onStart()
Future<void> onStart(ServiceInstance service) async {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
DartPluginRegistrant.ensureInitialized();
int minutes = 0;
int seconds = 10;
service.on("stopService").listen((event) {
service.stopSelf();
});
Timer.periodic(const Duration(seconds: 1), (timer) async {
// one minute completed
if (seconds == 60) {
// reset seconds
seconds = 0;
// increment minutes
minutes++;
}
simpleNotification(
minutes: minutes,
seconds: seconds,
flutterLocalNotificationsPlugin: flutterLocalNotificationsPlugin,
);
// increment seconds every second
seconds++;
});
}
I'll be grateful for your help.

Flutter: separating background service to different class, cause method error

Hi so I'm trying to use background_service for my app by using flutter_background_service plugin, I've managed to follow the example from the documentation and I want to move these function to different classes for better code writing. The problem is when I move it to the other file and call the method it show an error of:
Unhandled Exception: onStart method must be a top-level or static function
What causing this to happen ? can anyone explain it and how to fix it ? And how do I make my background_service app listen to my firestore data.. I want to detect if there's any task that almost pass the due_date.
Here's my code:
Main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await BackgroundService().initializeService();
}
Background_service.dart
class BackgroundService {
static const notificationChannelId = 'my_foreground';
static const notificationId = 888;
Future<void> initializeService() async {
final service = FlutterBackgroundService();
const AndroidNotificationChannel channel = AndroidNotificationChannel(
notificationChannelId, // ID
'MY FOREGROUND SERVICE', // Title
description:
'This channel is used for important notifications.', // Description
importance: Importance.low, // importance must be at low or higher level
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
if (Platform.isIOS) {
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
iOS: IOSInitializationSettings(),
),
);
}
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: _onIosBackground,
),
);
service.startService();
}
onStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
/// Code about _onstrat method
}
#pragma('vm:entry-point')
Future<bool> _onIosBackground(ServiceInstance service) async {
/// Code about Ios background
}
}
top-level means the function should be sits on the top of any
hierarchy of Class or Function.
you have to put the fucntion outside of classes. read documentation here: https://dart.dev/guides/language/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members
Workaround:
background_service.dart
// on start is a top-level function
#pragma('vm:entry-point')
onStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
/// Code about _onstrat method
}
// top-level function
#pragma('vm:entry-point')
Future<bool> _onIosBackground(ServiceInstance service) async {
/// Code about Ios background
}
class BackgroundService {
static const notificationChannelId = 'my_foreground';
static const notificationId = 888;
......
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
),
iosConfiguration: IosConfiguration(
onForeground: onStart,
onBackground: _onIosBackground,
),
.......

How to access android Accessibility Service events from background service?

I am trying to access Accessibility from my background service app which uses flutter_background_service plugin. But I can't listen to the Accessibility events. I am also receiving an error:
Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: x-slayer/accessibility_event. Response ID: 34
But when the app is open(in recent app) the service is working fine. How do I fix it?
Here is my code. I am trying to fix this for a day, but cant find a way out:
Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
service.startService();
}
bool onIosBackground(ServiceInstance service) {
WidgetsFlutterBinding.ensureInitialized();
print('FLUTTER BACKGROUND FETCH');
return true;
}
void onStart(ServiceInstance service) async {
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
// For flutter prior to version 3.0.0
// We have to register the plugin manually
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
// bring to foreground
Timer.periodic(const Duration(seconds: 1), (timer) async {
if (service is AndroidServiceInstance) {
service.setForegroundNotificationInfo(
title: "My App Service",
content: "Updated at ${DateTime.now()}",
);
}
/// you can see this log in logcat
print('FLUTTER BACKGROUND SERVICE: ${DateTime.now()}');
void PeaceBox() {
StreamSubscription<AccessibilityEvent>? _subscription;
List<AccessibilityEvent?> events = [];
overlayRequest();
print("Started listening");
// FlutterOverlayWindow.overlayListener.listen((event) {
// print("$event");
// });
String text = "";
// print(text.split(" "));
FlutterAccessibilityService.accessStream.listen((event) {
});
}
PeaceBox();
// test using external plugin
final deviceInfo = DeviceInfoPlugin();
String? device;
if (Platform.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
device = androidInfo.model;
}
if (Platform.isIOS) {
final iosInfo = await deviceInfo.iosInfo;
device = iosInfo.model;
}
service.invoke(
'update',
{
"current_date": DateTime.now().toIso8601String(),
"device": device,
},
);
});
}

Crash in some device while using background service

I used flutter background service plug-in.Sometimes I getting crash.
I don't know why it is happening? is there any solution??
I tried it by many ways..It's very critical..
I am using flutter_background_service 1.0.4 as background services as well as foreground services.
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not
then call Service.startForeground(): ServiceRecord{67fd813 u0
com.example.sms_scheduler/id.flutter.flutter_background_service.BackgroundService}
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1797)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6651)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)
This is my Code !!
void main() async{
await initializeService();
runApp(const MyApp());
}
Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: onIosBackground,
),
);
}
void onIosBackground() {
WidgetsFlutterBinding.ensureInitialized();
print('FLUTTER BACKGROUND FETCH');
}
void onStart() {
if (Platform.isAndroid){PathProviderAndroid.registerWith();}
else if (Platform.isIOS){PathProviderIOS.registerWith();}
if (Platform.isIOS) FlutterBackgroundServiceIOS.registerWith();
if (Platform.isAndroid) FlutterBackgroundServiceAndroid.registerWith();
final service = FlutterBackgroundService();
service.onDataReceived.listen((event) {
if (event!["action"] == "setAsForeground") {
service.setAsForegroundService();
return;
}
if (event["action"] == "setAsBackground") {
service.setAsBackgroundService();
}
if (event["action"] == "stopService") {
service.stopService();
}
});
service.setAsBackgroundService();
Timer.periodic(const Duration(seconds: 05), (timer) async {
service.sendData(
{
"final_sms": sendFinalSMS(),
}
);
});
}
Why don't you use this
try{
//code that may throw an exception
}catch(Exception_class_Name ref){}

Service wont initialize when exported to seperate class

Whenever I am trying to launch background service from a seperate class then it doesn't work at all, nothing happens. However when I include all the methods under void main() in main.dart file and in main use await initializeService(); then it works. Why I can't launch this from an external class that I have created? I don't want to keep all the methods in the main file because it's getting messy. Am I doing something wrong? I am using this library
https://pub.dev/packages/flutter_background_service
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await BackgroundService().initializeService();
child: const MyApp()));
}
class BackgroundService {
Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
}
// to ensure this executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch
void onIosBackground() {
WidgetsFlutterBinding.ensureInitialized();
print('FLUTTER BACKGROUND FETCH');
}
void onStart() {
WidgetsFlutterBinding.ensureInitialized();
final service = FlutterBackgroundService();
service.onDataReceived.listen((event) {
if (event!["action"] == "setAsForeground") {
service.setForegroundMode(true);
return;
}
if (event["action"] == "setAsBackground") {
service.setForegroundMode(false);
}
if (event["action"] == "stopService") {
service.stopBackgroundService();
}
});
// bring to foreground
service.setForegroundMode(true);
Timer.periodic(const Duration(seconds: 3), (timer) async {
if (!(await service.isServiceRunning())) timer.cancel();
service.setNotificationInfo(
title: "My App Service",
content: "Updated at ${DateTime.now()}",
);
print("Hello");
service.sendData(
{
"current_date": DateTime.now().toIso8601String(),
// "device": device,
},
);
});
}
}