Hi I want my android app work in background even if the program completely close(terminate). I use the flutter_background_fetch for it. the notification show every 15 min correctly in app is open or go to background, But when I terminate app the background_fetch not work and not show the notification or do anything anymore.
here this my main file config:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
initializeNotificationService();
runApp(const MyApp());
}
#pragma('vm:entry-point')
void backgroundFetchHeadlessTask(HeadlessTask task) async {
String taskId = task.taskId;
bool isTimeout = task.timeout;
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
BackgroundFetch.finish(taskId);
return;
}
// Do your work here...
BackgroundFetch.finish(taskId);
}
and this is part of my controller body for background_fetch:
class Controller extends GetxController {
#override
void onInit() {
// TODO: implement onInit
super.onInit();
startListeningNotificationEvents();
initPlatformState();
}
Future<void> initPlatformState() async {
var status = await BackgroundFetch.configure(
BackgroundFetchConfig(
minimumFetchInterval: 15,
forceAlarmManager: false,
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresStorageNotLow: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.NONE,
),
_onBackgroundFetch,
_onBackgroundFetchTimeout);
BackgroundFetch.scheduleTask(TaskConfig(
taskId: "test",
delay: 1000,
periodic: false,
stopOnTerminate: false,
enableHeadless: true));
BackgroundFetch.start();
}
void _onBackgroundFetchTimeout(String taskId) {
//BackgroundFetch.finish(taskId);
}
void _onBackgroundFetch(String taskId) async {
if (taskId == "test") {
random();
createNotification();
}
}
}
in the document said if we want app work even after terminate, we should set the "stopOnTerminate" equals false. but still not working. how can fix this? please help.
Related
I have an app based on flutter and created a Home screen widget for android (with home_widget) showing information from the app. With flutter background_fetch I update these information regularly, which works fine. Now when I restart my phone (emulator or real device), the background_fetch task does not continue, despite headless: true and stopOnTerminate: false set. Instead the old information from the latest fetch before the restart are displayed in the widget again.
main.dart
import 'package:home_widget/home_widget.dart';
import 'package:background_fetch/background_fetch.dart';
import 'package:logging_to_logcat/logging_to_logcat.dart';
import 'package:logging/logging.dart';
void main() {
runApp(
const MaterialApp(
home: MyApp()
)
);
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
}
// [Android-only] This "Headless Task" is run when the Android app is terminated with `enableHeadless: true`
// Be sure to annotate your callback function to avoid issues in release mode on Flutter >= 3.3.0
#pragma('vm:entry-point')
void backgroundFetchHeadlessTask(HeadlessTask task) async {
String taskId = task.taskId;
bool isTimeout = task.timeout;
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
debugPrint("[BackgroundFetch] Headless task timed-out: $taskId");
BackgroundFetch.finish(taskId);
return;
}
HomeWidget.saveWidgetData('refresh_date', "restarted");
HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge');
debugPrint('[BackgroundFetch] Headless event received.');
BackgroundFetch.finish(taskId);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State createState() {
return MainPage();
}
}
class MainPage extends State {
#override
void initState() {
super.initState();
initPlatformState();
BackgroundFetch.start().then((int status) {
debugPrint('[BackgroundFetch] start success: $status');
}).catchError((e) {
debugPrint('[BackgroundFetch] start FAILURE: $e');
});
HomeWidget.saveWidgetData('refresh_date', "test2");
HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge');
}
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
// Configure BackgroundFetch.
int status = await BackgroundFetch.configure(BackgroundFetchConfig(
minimumFetchInterval: 15,
stopOnTerminate: false,
enableHeadless: true,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresStorageNotLow: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.ANY,
startOnBoot: true,
forceAlarmManager: true
), (String taskId) async { // <-- Event handler
// This is the fetch-event callback.
print("[BackgroundFetch] Event received $taskId");
setState(() {
latestUpdate = DateTime.now();
HomeWidget.saveWidgetData('refresh_date', "test");
HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge');
});
// IMPORTANT: You must signal completion of your task or the OS can punish your app
// for taking too long in the background.
BackgroundFetch.finish(taskId);
}, (String taskId) async { // <-- Task timeout handler.
// This task has exceeded its allowed running-time. You must stop what you're doing and immediately .finish(taskId)
debugPrint("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
BackgroundFetch.finish(taskId);
});
debugPrint('[BackgroundFetch] configure success: $status');
// 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;
}
}
I import background_fetch like this:
dependencies:
...
home_widget: ^0.1.6
background_fetch:
git:
url: https://github.com/transistorsoft/flutter_background_fetch
I just updated flutter to the latest version with flutter upgrade and now it's working. Even tough the headless task begins executing 15 minutes after the reboot, so I still try to figure out how do execute it immediately after the reboot.
I integrated the flutter app with firebase.
I have no problem with getting push notifications when the app is in background, but I don't get foreground notifications.
I added handling foreground messages, now it throws FirebaseException ([core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()), although I have added initilalizeApp() in main method.
that is my main:
WidgetsFlutterBinding.ensureInitialized();
Firebase.initializeApp().then((value) => print("Firebase initialized"));
runApp(const MyApp());
and that is how I handled foreground notifications in MyApp:
// It is assumed that all messages contain a data field with the key 'type'
Future<void> setupInteractedMessage() async {
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "chat",
// navigate to a chat screen
if (initialMessage != null) {
_handleMessage(initialMessage);
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
void _listenForMessages() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) {
setState(() {
String? body = message.notification?.body;
if (body != null) {
} else {}
});
}
});
}
void _handleMessage(RemoteMessage message) {
if (message.data['type'] == 'chat') {
Navigator.pushNamed(
context,
'/chat',
arguments: message,
);
}
}
#override
void initState() {
super.initState();
_requestPermission();
setupInteractedMessage();
_listenForMessages();
}
void _requestPermission() async {
NotificationSettings settings =
await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
} else if (settings.authorizationStatus ==
AuthorizationStatus.provisional) {
} else {}
}
all I found on internet for that error it says call initilazieApp() in main method, but I have done that already but the error won't go away.
Use await Firebase.initializeApp();
you have to add the await
so i'm creating an app like facebook,instagram ....
When i was in systeme notifications step, i managed to display notifications when the App state is Open or paused but not when the app is dettached (closed), i'm no longer able to recieve new local notifications.
i tried many packages like flutter_background_service and workmanager, i'm working with flutter_background_service now in debug mode all was good, but when i build the apk it's not working in background.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
AwesomeNotifications().initialize('resource://drawable/appicon', [
NotificationChannel(
channelKey: 'basic_channel',
channelName: 'basic Notifications',
channelDescription: "channelDescription",
importance: NotificationImportance.High,
enableVibration: true,
channelShowBadge: true,
)
]);
await Firebase.initializeApp(
name: 'firebase',
options: const FirebaseOptions(//firebaseconfig),
);
await initializeService();
runApp(MyApp());
}
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
// auto start service
autoStart: true,
onStart: onStart,
isForegroundMode: false,
),
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();
}
// to ensure this is executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch
bool onIosBackground(ServiceInstance service) {
WidgetsFlutterBinding.ensureInitialized();
print('FLUTTER BACKGROUND FETCH');
return true;
}
void onStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
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 {
/// you can see this log in logcat
print('FLUTTER BACKGROUND SERVICE is running : ${DateTime.now()}');
//////////////////////////////////////////////////////////////////////////////////////////
I want somthing like this: keep 2 getxcontroller working even if the app detached
//////////////////////////////////////////////////////////////////////////////////////////
await Firebase.initializeApp(
name: 'firebase',
options: const FirebaseOptions(//firebaseconfig),
).whenComplete(() {
final notifc = Get.put(Notificationsc());
final msgl = Get.put(MessageslistsController());
});
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
if (service is AndroidServiceInstance) {
service.setForegroundNotificationInfo(
title: "My App Service",
content: "Updated at ${DateTime.now()}",
);
}
// 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,
},
);
});
}
import BackgroundService from 'react-native-background-actions';
const sleep = (time) => new Promise((resolve) => setTimeout(() => resolve(), time));
// You can do anything in your task such as network requests, timers and so on,
// as long as it doesn't touch UI. Once your task completes (i.e. the promise is resolved),
// React Native will go into "paused" mode (unless there are other tasks running,
// or there is a foreground app).
const veryIntensiveTask = async (taskDataArguments) => {
// Example of an infinite loop task
const { delay } = taskDataArguments;
await new Promise( async (resolve) => {
for (let i = 0; BackgroundService.isRunning(); i++) {
console.log(i);
await sleep(delay);
}
});
};
const options = {
taskName: 'Example',
taskTitle: 'ExampleTask title',
taskDesc: 'ExampleTask description',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourSchemeHere://chat/jane', // See Deep Linking for more info
parameters: {
delay: 1000,
},
};
await BackgroundService.start(veryIntensiveTask, options);
await BackgroundService.updateNotification({taskDesc: 'New ExampleTask description'}); // Only Android, iOS will ignore this call
// iOS will also run everything here in the background until .stop() is called
await BackgroundService.stop();
I am using react-native-background-actions. I need 2 buttons in this. But I don’t have any good experience with native code in react native so let me know how can I add custom buttons In it and changes buttons according condition. How can I make changes in the native android for notification buttons.
I want to update user's location in background.
To perform tasks in background, i used this package, workmanager.
Link to that: https://pub.dev/packages/workmanager
But i can not update the location, it seems like it can't work with async code?
here is my code,
void callbackDispatcher() {
Workmanager.executeTask((task, inputData) async {
await _HomeScreenState().updateUserLoc();
print('it is working?');
return Future.value(true);
});
}
//Inside my stateFul Widget,
void initState() {
super.initState();
Workmanager.initialize(
callbackDispatcher,
isInDebugMode: true,
);
Workmanager.registerPeriodicTask(
"1",
fetchBackground,
frequency: Duration(minutes: 15),
);
}
updateUserLoc() async {
print("executi9ng the updateUserLocccccc");
await getusersLocation();
print("executi9ng the updateUserLoc");
GeoFirePoint point = geo.point(latitude: lat, longitude: long);
_firestore.collection('locations').document(widget.userid).setData(
{'position': point.data},
merge: true,
);
}
Is there any other way of updating the users's location in background?
You have to call the call the code inside the updateUserLoc() directly inside the callbackDispatcher. Just make the callbackDispatcher async function.