Flutter前台任务管理插件flutter_foreground_task_native的使用
Flutter前台任务管理插件flutter_foreground_task_native的使用
本插件用于在Android平台上实现前台服务。
特性
- 可以通过前台服务执行重复任务。
- 提供有用的功能(最小化应用、唤醒屏幕等)可以在执行任务时使用。
- 提供一个可以防止应用程序在前台服务运行时关闭的小部件。
- 提供一个小部件,当应用被最小化或关闭时启动前台服务。
- 提供一个选项,可以在设备重启时自动恢复前台服务。
开始使用
要使用此插件,请在pubspec.yaml
文件中添加flutter_foreground_task
作为依赖。例如:
dependencies:
flutter_foreground_task_native: ^1.0.1
在将flutter_foreground_task
插件添加到Flutter项目后,我们需要指定权限和服务,以便该插件能够正常工作。
Android
由于此插件基于前台服务,因此需要向AndroidManifest.xml
文件中添加以下权限。打开AndroidManifest.xml
文件,并将其放在<manifest>
和<application>
标签之间。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
还需要添加此权限以便在启动时自动恢复前台服务。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
并指定服务,如下所示:
<service android:name="com.pravera.flutter_foreground_task.service.ForegroundService" />
iOS
我们也可以在iOS平台上启动flutter_foreground_task
。然而,它有以下限制:
- 仅适用于iOS 10.0或更高版本。
- 如果应用程序被强制关闭,任务将不会工作。
- 无法在设备重新启动时自动启动任务。
- 由于平台的后台处理限制,
onEvent
事件可能无法在后台正常工作。但在前台运行时表现良好。
Objective-C:
-
若要在使用Objective-C的项目中使用用Swift语言开发的插件,你需要添加桥接头文件。如果你的项目中没有
ios/Runner/Runner-Bridging-Header.h
文件,请参阅此页面。 -
打开
ios/Runner/AppDelegate.swift
文件并添加注释代码。
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
// here
#import <flutter_foreground_task/FlutterForegroundTaskPlugin.h>
// here
void registerPlugins(NSObject<FlutterPluginRegistry>* registry) {
[GeneratedPluginRegistrant registerWithRegistry:registry];
}
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// here, Without this code the task will not work.
[FlutterForegroundTaskPlugin setPluginRegistrantCallback:registerPlugins];
if (@available(iOS 10.0, *)) {
[UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
}
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
Swift:
- 在
ios/Runner/Runner-Bridging-Header.h
文件中声明导入语句。
#import <flutter_foreground_task/FlutterForegroundTaskPlugin.h>
- 打开
ios/Runner/AppDelegate.swift
文件并添加注释代码。
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
// here, Without this code the task will not work.
SwiftFlutterForegroundTaskPlugin.setPluginRegistrantCallback(registerPlugins)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
// here
func registerPlugins(registry: FlutterPluginRegistry) {
GeneratedPluginRegistrant.register(with: registry)
}
如何使用
此插件有两种方式启动前台任务。一种是手动启动前台任务,另一种是在应用最小化或关闭时通过WillStartForegroundTask
小部件启动。
手动启动
- 初始化
FlutterForegroundTask
。你可以使用FlutterForegroundTask.init()
函数来设置通知和任务选项。
Future<void> _initForegroundTask() async {
await FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'notification_channel_id',
channelName: 'Foreground Notification',
channelDescription: 'This notification appears when the foreground service is running.',
channelImportance: NotificationChannelImportance.LOW,
priority: NotificationPriority.LOW,
iconData: const NotificationIconData(
resType: ResourceType.mipmap,
resPrefix: ResourcePrefix.ic,
name: 'launcher',
),
buttons: [
const NotificationButton(id: 'sendButton', text: 'Send'),
const NotificationButton(id: 'testButton', text: 'Test'),
],
),
iosNotificationOptions: const IOSNotificationOptions(
showNotification: true,
playSound: false,
),
foregroundTaskOptions: const ForegroundTaskOptions(
interval: 5000,
autoRunOnBoot: true,
allowWifiLock: true,
),
printDevLog: true,
);
}
@override
void initState() {
super.initState();
_initForegroundTask();
}
- 添加
WithForegroundTask
小部件以防止应用在前台服务运行时关闭。
@override
Widget build(BuildContext context) {
return MaterialApp(
// A widget that prevents the app from closing when the foreground service is running.
// This widget must be declared above the [Scaffold] widget.
home: WithForegroundTask(
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Foreground Task'),
centerTitle: true,
),
body: buildContentView(),
),
),
);
}
- 编写回调和处理器并启动前台服务。
FlutterForegroundTask.startService()
提供了以下选项:
// The callback function should always be a top-level function.
void startCallback() {
// The setTaskHandler function must be called to handle the task in the background.
FlutterForegroundTask.setTaskHandler(FirstTaskHandler());
}
class FirstTaskHandler extends TaskHandler {
@override
Future<void> onStart(DateTime timestamp, SendPort? sendPort) async {
// You can use the getData function to get the data you saved.
final customData = await FlutterForegroundTask.getData<String>(key: 'customData');
print('customData: $customData');
}
@override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async {
// Send data to the main isolate.
sendPort?.send(timestamp);
}
@override
Future<void> onDestroy(DateTime timestamp) async {
// You can use the clearAllData function to clear all the stored data.
await FlutterForegroundTask.clearAllData();
}
@override
void onButtonPressed(String id) {
// Called when the notification button on the Android platform is pressed.
print('onButtonPressed >> $id');
}
}
class ExampleApp extends StatefulWidget {
const ExampleApp({Key? key}) : super(key: key);
@override
_ExampleAppState createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
ReceivePort? _receivePort;
Future<bool> _startForegroundTask() async {
// You can save data using the saveData function.
await FlutterForegroundTask.saveData(key: 'customData', value: 'hello');
ReceivePort? receivePort;
if (await FlutterForegroundTask.isRunningService) {
receivePort = await FlutterForegroundTask.restartService();
} else {
receivePort = await FlutterForegroundTask.startService(
notificationTitle: 'Foreground Service is running',
notificationText: 'Tap to return to the app',
callback: startCallback,
);
}
if (receivePort != null) {
_receivePort = receivePort;
_receivePort?.listen((message) {
if (message is DateTime) {
print('receive timestamp: $message');
}
});
return true;
}
return false;
}
@override
void dispose() {
_receivePort?.close();
super.dispose();
}
}
如你所见,你可以使用以下功能管理数据:
void function() async {
await FlutterForegroundTask.getData(key: String);
await FlutterForegroundTask.saveData(key: String, value: Object);
await FlutterForegroundTask.removeData(key: String);
await FlutterForegroundTask.clearAllData();
}
如果插件提供了流,可以这样使用:
class FirstTaskHandler extends TaskHandler {
StreamSubscription<Position>? streamSubscription;
@override
Future<void> onStart(DateTime timestamp, SendPort? sendPort) async {
final positionStream = Geolocator.getPositionStream();
streamSubscription = positionStream.listen((event) {
// Update notification content.
FlutterForegroundTask.updateService(
notificationTitle: 'Current Position',
notificationText: '${event.latitude}, ${event.longitude}');
// Send data to the main isolate.
sendPort?.send(event);
});
}
@override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async {
}
@override
Future<void> onDestroy(DateTime timestamp) async {
await streamSubscription?.cancel();
}
}
- 使用
FlutterForegroundTask.updateService()
更新前台服务。选项与启动函数相同。
// The callback function should always be a top-level function.
void startCallback() {
// The setTaskHandler function must be called to handle the task in the background.
FlutterForegroundTask.setTaskHandler(FirstTaskHandler());
}
class FirstTaskHandler extends TaskHandler {
int updateCount = 0;
@override
Future<void> onStart(DateTime timestamp, SendPort? sendPort) async {
}
@override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async {
FlutterForegroundTask.updateService(
notificationTitle: 'FirstTaskHandler',
notificationText: timestamp.toString(),
callback: updateCount >= 10 ? updateCallback : null);
// Send data to the main isolate.
sendPort?.send(timestamp);
sendPort?.send(updateCount);
updateCount++;
}
@override
Future<void> onDestroy(DateTime timestamp) async {
}
}
void updateCallback() {
FlutterForegroundTask.setTaskHandler(SecondTaskHandler());
}
class SecondTaskHandler extends TaskHandler {
@override
Future<void> onStart(DateTime timestamp, SendPort? sendPort) async {
}
@override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async {
FlutterForegroundTask.updateService(
notificationTitle: 'SecondTaskHandler',
notificationText: timestamp.toString());
// Send data to the main isolate.
sendPort?.send(timestamp);
}
@override
Future<void> onDestroy(DateTime timestamp) async {
}
}
- 如果不再使用前台服务,调用
FlutterForegroundTask.stopService()
。
Future<bool> _stopForegroundTask() async {
return await FlutterForegroundTask.stopService();
}
使用WillStartForegroundTask
小部件启动
@override
Widget build(BuildContext context) {
return MaterialApp(
// A widget to start the foreground service when the app is minimized or closed.
// This widget must be declared above the [Scaffold] widget.
home: WillStartForegroundTask(
onWillStart: () async {
// Return whether to start the foreground service.
return true;
},
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'notification_channel_id',
channelName: 'Foreground Notification',
channelDescription: 'This notification appears when the foreground service is running.',
channelImportance: NotificationChannelImportance.LOW,
priority: NotificationPriority.LOW,
iconData: NotificationIconData(
resType: ResourceType.mipmap,
resPrefix: ResourcePrefix.ic,
name: 'launcher',
),
),
iosNotificationOptions: const IOSNotificationOptions(
showNotification: true,
playSound: false,
),
foregroundTaskOptions: const ForegroundTaskOptions(
interval: 5000,
autoRunOnBoot: false,
allowWifiLock: false,
),
printDevLog: true,
notificationTitle: 'Foreground Service is running',
notificationText: 'Tap to return to the app',
callback: startCallback,
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Foreground Task'),
centerTitle: true,
),
body: buildContentView(),
),
),
);
}
模型
AndroidNotificationOptions
Android平台的通知选项。
属性 | 描述 |
---|---|
channelId |
通知渠道的唯一ID。 |
channelName |
通知渠道的名称。此值在通知设置中显示给用户。 |
channelDescription |
通知渠道的描述。此值在通知设置中显示给用户。 |
channelImportance |
通知渠道的重要性。默认为NotificationChannelImportance.DEFAULT 。 |
priority |
Android 7.1及以下版本的通知优先级。默认为NotificationPriority.DEFAULT 。 |
enableVibration |
创建通知时是否启用振动。默认为false 。 |
playSound |
创建通知时是否播放声音。默认为false 。 |
showWhen |
是否在内容视图中显示通知创建的时间戳。默认为false 。 |
isSticky |
系统是否会重新启动服务,如果服务被杀死。默认为true 。 |
visibility |
控制在锁定屏幕上显示的通知详细程度。默认为NotificationVisibility.VISIBILITY_PUBLIC 。 |
iconData |
在通知中显示的图标数据。如果值为空,则使用应用程序启动器图标。 |
buttons |
在通知中显示的按钮列表。最多允许三个。 |
NotificationIconData
设置通知图标的数据。
属性 | 描述 |
---|---|
resType |
通知图标的资源类型。如果资源在drawable文件夹中,则设置为ResourceType.drawable ;如果资源在mipmap文件夹中,则设置为ResourceType.mipmap 。 |
resPrefix |
通知图标的资源前缀。如果通知图标名称为ic_simple_notification ,则设置为ResourcePrefix.ic ,并将name 设置为simple_notification 。 |
name |
不带前缀的通知图标名称。 |
ResourceType
通知图标的资源类型。
值 | 描述 |
---|---|
drawable |
存储在drawable文件夹中的资源。drawable文件夹用于存储各种图像。 |
mipmap |
存储在mipmap文件夹中的资源。mipmap文件夹通常用于存储启动器图标图像。 |
ResourcePrefix
通知图标的资源前缀。
值 | 描述 |
---|---|
ic |
具有ic_ 前缀的资源。 |
img |
具有img_ 前缀的资源。 |
NotificationButton
在通知中显示的按钮。
属性 | 描述 |
---|---|
id |
按钮标识符。 |
text |
显示在按钮上的文本。 |
IOSNotificationOptions
iOS平台的通知选项。
属性 | 描述 |
---|---|
showNotification |
是否显示通知。默认为true 。 |
playSound |
创建通知时是否播放声音。默认为false 。 |
ForegroundTaskOptions
包含前台任务选项的数据类。
属性 | 描述 |
---|---|
interval |
任务调用间隔时间(毫秒)。默认为5000 。 |
autoRunOnBoot |
是否在启动时自动运行前台任务。默认为false 。 |
allowWifiLock |
允许应用程序保持Wi-Fi无线电唤醒。默认为false 。 |
NotificationChannelImportance
通知渠道的重要性。
值 | 描述 |
---|---|
NONE |
没有重要性的通知:不会在阴影中显示。 |
MIN |
最低通知重要性:仅在阴影中显示,位于折叠部分。 |
LOW |
低通知重要性:在阴影中显示,并可能在状态栏中显示(参见shouldHideSilentStatusBarIcons() ),但不会发出听觉干扰。 |
DEFAULT |
默认通知重要性:在所有地方显示,发出声音,但不会视觉干扰。 |
HIGH |
较高的通知重要性:在所有地方显示,发出声音并弹出。可能使用全屏意图。 |
MAX |
最大通知重要性:与HIGH相同,但通常不使用。 |
NotificationPriority
Android 7.1及以下版本的通知优先级。
值 | 描述 |
---|---|
MIN |
没有声音且不会出现在状态栏中。 |
LOW |
没有声音。 |
DEFAULT |
发出声音。 |
HIGH |
发出声音并以抬头通知的形式出现。 |
MAX |
与HIGH相同,但在需要立即通知时使用。 |
NotificationVisibility
在锁定屏幕上显示的通知详细程度。
值 | 描述 |
---|---|
VISIBILITY_PUBLIC |
在所有锁定屏幕上完全显示此通知。 |
VISIBILITY_SECRET |
在安全锁定屏幕上不显示此通知的任何部分。 |
VISIBILITY_PRIVATE |
在所有锁定屏幕上显示此通知,但在安全锁定屏幕上隐藏敏感或私人信息。 |
工具方法
minimizeApp (Both)
最小化应用程序到后台。
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
void function() => FlutterForegroundTask.minimizeApp();
wakeUpScreen (Android)
唤醒关机设备的屏幕。
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
void function() => FlutterForegroundTask.wakeUpScreen();
isIgnoringBatteryOptimizations (Android)
返回应用程序是否已排除电池优化。
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
Future<bool> function() => FlutterForegroundTask.isIgnoringBatteryOptimizations;
openIgnoreBatteryOptimizationSettings (Android)
打开设置页面,可以设置忽略电池优化。
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
Future<bool> function() => FlutterForegroundTask.openIgnoreBatteryOptimizationSettings();
requestIgnoreBatteryOptimization (Android)
请求忽略电池优化。此功能需要android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
权限。
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
Future<bool> function() => FlutterForegroundTask.requestIgnoreBatteryOptimization();
更多关于Flutter前台任务管理插件flutter_foreground_task_native的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html