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){}
Related
import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../export.dart';
class FirebaseNotificationManager {
FirebaseNotificationManager._privateConstructor();
static final FirebaseNotificationManager _instance = FirebaseNotificationManager._privateConstructor();
factory FirebaseNotificationManager() {
return _instance;
}
init() async {
// add firebase notification permission
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: true,
provisional: false,
sound: true,
);
if (await Permission.notification.request().isGranted) {
try {
// Either the permission was already granted before or the user just granted it.
FirebaseMessaging.onBackgroundMessage(_messageHandler);
_firebaseMessagingListener();
String? deviceToken = await FirebaseMessaging.instance.getToken();
logger.i(deviceToken);
} catch (e) {
logger.i(e);
}
}
}
/// must call it from view after getContext is initialized to show dialog message
checkAndroid() async {
if (!(await Permission.notification.request().isGranted) && GetPlatform.isAndroid) {
showOptionsDialog(
text: 'إذا كنت ترغب في تلقي الاشعارات ،برجاء اعطاء إذن الاشعارات في الإعدادات وإعادة تشغيل التطبيق',
yesFunction: (context) async {
openAppSettings();
});
}
}
// execute if app in background
Future<void> _messageHandler(RemoteMessage message) async {
// Data notificationMessage = Data.fromJson(message.data);
log('notification from background : ${message.toMap()}');
}
// execute if app in foreground
void _firebaseMessagingListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
logger.i('Got a message whilst in the foreground!');
logger.i('Message data: ${message.data}');
if (message.notification != null) {
logger.i('Message also contained a notification: ${message.notification!.toMap()}');
logger.i('Message also contained a notification: ${message.toMap()}');
// that means new message
try {
Get.snackbar(message.notification!.title.toString(), message.notification!.body.toString(),
duration: Duration(seconds: 6),
backgroundColor: Theme.of(Get.context!).cardColor,
barBlur: 10,
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(8));
} catch (e) {
logger.i(e);
}
}
});
}
}
As per the documentation, you need to put the onBackgroundMessage function outside of a class, at the top of your file as a top-level function. See Firebase messaging example for implementation.
source
file became:
import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../export.dart';
init() async {
// add firebase notification permission
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: true,
provisional: false,
sound: true,
);
if (await Permission.notification.request().isGranted) {
try {
// Either the permission was already granted before or the user just granted it.
FirebaseMessaging.onBackgroundMessage(_messageHandler);
_firebaseMessagingListener();
String? deviceToken = await FirebaseMessaging.instance.getToken();
logger.i(deviceToken);
} catch (e) {
logger.i(e);
}
}
}
/// must call it from view after getContext is initialized to show dialog message
checkAndroid() async {
if (!(await Permission.notification.request().isGranted) && GetPlatform.isAndroid) {
showOptionsDialog(
text: 'إذا كنت ترغب في تلقي الاشعارات ،برجاء اعطاء إذن الاشعارات في الإعدادات وإعادة تشغيل التطبيق',
yesFunction: (context) async {
openAppSettings();
});
}
}
// execute if app in background
Future<void> _messageHandler(RemoteMessage message) async {
// Data notificationMessage = Data.fromJson(message.data);
log('notification from background : ${message.toMap()}');
}
// execute if app in foreground
void _firebaseMessagingListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
logger.i('Got a message whilst in the foreground!');
logger.i('Message data: ${message.data}');
if (message.notification != null) {
logger.i('Message also contained a notification: ${message.notification!.toMap()}');
logger.i('Message also contained a notification: ${message.toMap()}');
// that means new message
try {
Get.snackbar(message.notification!.title.toString(), message.notification!.body.toString(),
duration: Duration(seconds: 6),
backgroundColor: Theme.of(Get.context!).cardColor,
barBlur: 10,
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(8));
} catch (e) {
logger.i(e);
}
}
});
}
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,
},
);
});
}
I'm using awesome_notifications and flutter_background_service in conjunction to update some app state when receiving data notifications from FirebaseMessaging. As noted in the awesome_notifications, the background message handler must be a top-level function, so I am using flutter_background_service to pass data to the main isolate and update app state.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeBackgroundService();
FirebaseMessaging.onBackgroundMessage(_backgroundMessageHandler);
_initLocalNotifications();
runApp(MyApp());
}
I'm initializing the background service similarly to the example in flutter_background_service:
Future<void> initializeBackgroundService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: onIosBackground,
),
);
await service.startService();
}
and invoking update in the _backgroundMessageHandler when a notification is received:
Future<void> _backgroundMessageHandler(
RemoteMessage message,
) async {
final service = FlutterBackgroundService();
...
service.invoke('update', {
'key1': 'val1',
'key2': 'val2',
});
}
And in the StatefulWidget for my app in the main isolate, I'm listening on the update call to receive the data:
void listenForNotificationData() {
final backgroundService = FlutterBackgroundService();
backgroundService.on('update').listen((event) async {
print('received data message in feed: $event');
}, onError: (e, s) {
print('error listening for updates: $e, $s');
}, onDone: () {
print('background listen closed');
});
}
It's never invoking the listen callback on the 'update' event. I can confirm it's calling the invoke('update') portion and calling on('update').listen, but never receiving the update. It also doesn't seem to be erroring out. Am I missing a step somewhere here?
I was encountering the same issue on flutter background service. I solved it by removing the async keyword from the callback and creating a separate async function to perform the callback operations.
void listenForNotificationData() {
final backgroundService = FlutterBackgroundService();
backgroundService.on('update').listen((event) {
print('received data message in feed: $event');
}, onError: (e, s) {
print('error listening for updates: $e, $s');
}, onDone: () {
print('background listen closed');
});
}
void action(Map? event) async {
print('received data message in feed: $event');
}
Hope it helps, forgive me if there are syntax error
You can try this.
main(){
....
}
Future<void> readyForShared() async {
var sharedPreferences = await SharedPreferences.getInstance();
counterValue = sharedPreferences.getString("yourVariable") ?? "0";
}
Future<void> saveData(String value) async {
var sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("yourVariable", value);
}
#pragma('vm:entry-point')
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
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString("hello", "world");
/// OPTIONAL when use custom notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
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 {
final receivePort = ReceivePort();
// here we are passing method name and sendPort instance from ReceivePort as listener
await Isolate.spawn(computationallyExpensiveTask, receivePort.sendPort);
if (service is AndroidServiceInstance) {
if (await service.isForegroundService()) {
//It will listen for isolate function to finish
// receivePort.listen((sum) {
// flutterLocalNotificationsPlugin.show(
// 888,
// 'Title',
// 'Description ${DateTime.now()}',
// const NotificationDetails(
// android: AndroidNotificationDetails(
// 'my_foreground',
// 'MY FOREGROUND SERVICE',
// icon: 'ic_bg_service_small',
// ongoing: true,
// ),
// ),
// );
// });
var sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.reload(); // Its important
service.setForegroundNotificationInfo(
title: "My App Service",
content: "Updated at ${sharedPreferences.getString("yourVariable") ?? 'no data'}",
);
}
}
/// you can see this log in logcat
if (kDebugMode) {
// print('FLUTTER BACKGROUND SERVICE: ${deee.toString()}');
}
// 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": '400',
"device": device,
},
);
});
}
....
....
....
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
readyForShared(); // init shared preferences
});
}
...
...
...
ElevatedButton(onPressed:(){saveData('Your Updated data.');}....
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,
),
);
}
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,
},
);
});
}
}