flutter_foreground_task 7.5.2 flutter_foreground_task: ^7.5.2 copied to clipboard
This plugin is used to implement a foreground service on the Android platform.
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
void main() => runApp(const ExampleApp());
// The callback function should always be a top-level function.
@pragma('vm:entry-point')
void startCallback() {
// The setTaskHandler function must be called to handle the task in the background.
FlutterForegroundTask.setTaskHandler(MyTaskHandler());
}
class MyTaskHandler extends TaskHandler {
int _count = 0;
// Called when the task is started.
@override
void onStart(DateTime timestamp, SendPort? sendPort) async {
print('onStart');
}
// Called every [interval] milliseconds in [ForegroundTaskOptions].
@override
void onRepeatEvent(DateTime timestamp, SendPort? sendPort) async {
FlutterForegroundTask.updateService(notificationText: 'count: $_count');
// Send data to the main isolate.
sendPort?.send(_count);
_count++;
}
// Called when the task is destroyed.
@override
void onDestroy(DateTime timestamp, SendPort? sendPort) async {
print('onDestroy');
}
// Called when data is sent using [FlutterForegroundTask.sendData].
@override
void onReceiveData(Object data) {
print('onReceiveData: $data');
}
// Called when the notification button on the Android platform is pressed.
@override
void onNotificationButtonPressed(String id) {
print('onNotificationButtonPressed >> $id');
}
// Called when the notification itself on the Android platform is pressed.
//
// "android.permission.SYSTEM_ALERT_WINDOW" permission must be granted for
// this function to be called.
@override
void onNotificationPressed() {
FlutterForegroundTask.launchApp('/');
print('onNotificationPressed');
}
// Called when the notification itself on the Android platform is dismissed
// on Android 14 which allow this behaviour.
@override
void onNotificationDismissed() {
print('onNotificationDismissed');
}
}
class ExampleApp extends StatelessWidget {
const ExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'/': (context) => const ExamplePage(),
},
initialRoute: '/',
);
}
}
class ExamplePage extends StatefulWidget {
const ExamplePage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _ExamplePageState();
}
class _ExamplePageState extends State<ExamplePage> {
ReceivePort? _receivePort;
Future<void> _requestPermissionForAndroid() async {
if (!Platform.isAndroid) {
return;
}
// "android.permission.SYSTEM_ALERT_WINDOW" permission must be granted for
// onNotificationPressed function to be called.
//
// When the notification is pressed while permission is denied,
// the onNotificationPressed function is not called and the app opens.
//
// If you do not use the onNotificationPressed or launchApp function,
// you do not need to write this code.
if (!await FlutterForegroundTask.canDrawOverlays) {
// This function requires `android.permission.SYSTEM_ALERT_WINDOW` permission.
await FlutterForegroundTask.openSystemAlertWindowSettings();
}
// Android 12 or higher, there are restrictions on starting a foreground service.
//
// To restart the service on device reboot or unexpected problem, you need to allow below permission.
if (!await FlutterForegroundTask.isIgnoringBatteryOptimizations) {
// This function requires `android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` permission.
await FlutterForegroundTask.requestIgnoreBatteryOptimization();
}
// Android 13 and higher, you need to allow notification permission to expose foreground service notification.
final NotificationPermission notificationPermissionStatus =
await FlutterForegroundTask.checkNotificationPermission();
if (notificationPermissionStatus != NotificationPermission.granted) {
await FlutterForegroundTask.requestNotificationPermission();
}
}
void _initForegroundTask() {
FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'foreground_service',
channelName: 'Foreground Service Notification',
channelDescription:
'This notification appears when the foreground service is running.',
channelImportance: NotificationChannelImportance.LOW,
priority: NotificationPriority.LOW,
),
iosNotificationOptions: const IOSNotificationOptions(
showNotification: false,
playSound: false,
),
foregroundTaskOptions: const ForegroundTaskOptions(
interval: 5000,
isOnceEvent: false,
autoRunOnBoot: true,
autoRunOnMyPackageReplaced: true,
allowWakeLock: true,
allowWifiLock: true,
),
);
}
Future<void> _startForegroundTask() async {
// Register the receivePort before starting the service.
final ReceivePort? receivePort = FlutterForegroundTask.receivePort;
final bool isRegistered = _registerReceivePort(receivePort);
if (!isRegistered) {
print('Failed to register receivePort!');
return;
}
ServiceRequestResult requestResult;
if (await FlutterForegroundTask.isRunningService) {
requestResult = await FlutterForegroundTask.restartService();
} else {
requestResult = await FlutterForegroundTask.startService(
notificationTitle: 'Foreground Service is running',
notificationText: 'Tap to return to the app',
notificationIcon: null,
notificationButtons: [
const NotificationButton(
id: 'btn_hello',
text: 'hello',
textColor: Colors.orange,
),
],
callback: startCallback,
);
}
// handle error
if (!requestResult.success) {
final Object? error = requestResult.error;
print('error: $error');
}
}
Future<void> _stopForegroundTask() async {
final ServiceRequestResult requestResult =
await FlutterForegroundTask.stopService();
// handle error
if (!requestResult.success) {
final Object? error = requestResult.error;
print('error: $error');
}
}
bool _registerReceivePort(ReceivePort? newReceivePort) {
if (newReceivePort == null) {
return false;
}
_closeReceivePort();
_receivePort = newReceivePort;
_receivePort?.listen(_onReceiveData);
return _receivePort != null;
}
void _closeReceivePort() {
_receivePort?.close();
_receivePort = null;
}
void _onReceiveData(dynamic data) {
if (data is int) {
print('count: $data');
} else if (data is Map<String, dynamic>) {
final dynamic timestampMillis = data["timestampMillis"];
if (timestampMillis != null) {
final DateTime timestamp =
DateTime.fromMillisecondsSinceEpoch(timestampMillis, isUtc: true);
print('timestamp: ${timestamp.toString()}');
}
}
}
void _sendData() {
final Random random = Random();
final int data = random.nextInt(100);
FlutterForegroundTask.sendData(data);
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await _requestPermissionForAndroid();
_initForegroundTask();
// You can get the previous ReceivePort without restarting the service.
if (await FlutterForegroundTask.isRunningService) {
final newReceivePort = FlutterForegroundTask.receivePort;
_registerReceivePort(newReceivePort);
}
});
}
@override
void dispose() {
_closeReceivePort();
super.dispose();
}
@override
Widget build(BuildContext context) {
// A widget that minimize the app without closing it when the user presses
// the soft back button. It only works when the service is running.
//
// This widget must be declared above the [Scaffold] widget.
return WithForegroundTask(
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Foreground Task'),
centerTitle: true,
),
body: _buildContentView(),
),
);
}
Widget _buildContentView() {
buttonBuilder(String text, {VoidCallback? onPressed}) {
return ElevatedButton(
onPressed: onPressed,
child: Text(text),
);
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
buttonBuilder('start service', onPressed: _startForegroundTask),
buttonBuilder('stop service', onPressed: _stopForegroundTask),
buttonBuilder('send random data', onPressed: _sendData),
],
),
);
}
}