Flutter后台任务管理插件workmanager的使用
Flutter后台任务管理插件workmanager的使用
简介
Flutter WorkManager 是一个用于在 Flutter 应用中执行后台任务的插件。它封装了 Android 的 WorkManager 和 iOS 的 performFetchWithCompletionHandler 以及 BGAppRefreshTask,允许在应用不在前台运行时执行 Dart 代码。
对于 iOS 用户,建议观看苹果官方提供的关于背景处理的介绍视频:WWDC2020 - Session 10063。视频中讨论的所有约束同样适用于此插件。
特点
- 支持一次性任务和周期性任务。
- 可以设置任务的初始延迟、约束条件(如网络类型、电量状态等)。
- 支持任务取消和重试机制。
- 提供详细的调试支持。
平台设置
为了正确调度后台任务,必须先完成 Android 和 iOS 的平台设置:
使用方法
初始化插件
在注册任何任务之前,必须初始化 WorkManager 插件:
import 'package:workmanager/workmanager.dart';
@pragma('vm:entry-point') // 必须添加,特别是在应用混淆或使用 Flutter 3.1+ 时
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) {
print("Native called background task: $task");
return Future.value(true);
});
}
void main() {
Workmanager().initialize(
callbackDispatcher, // 回调函数
isInDebugMode: true // 如果启用,会在任务运行时发布通知,便于调试
);
runApp(MyApp());
}
注册任务
一次性任务
注册一次性任务,任务只会执行一次:
Workmanager().registerOneOffTask(
"task-identifier",
"simpleTask",
initialDelay: Duration(minutes: 30), // 初始延迟时间
constraints: Constraints(
networkType: NetworkType.connected, // 需要网络连接
requiresCharging: true, // 需要充电
),
inputData: {'key': 'value'} // 输入数据
);
周期性任务
注册周期性任务,任务会定期执行:
Workmanager().registerPeriodicTask(
"periodic-task-identifier",
"simplePeriodicTask",
frequency: Duration(hours: 1), // 执行频率
);
示例代码
以下是一个完整的示例代码,展示了如何使用 workmanager
插件来注册和管理后台任务:
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workmanager/workmanager.dart';
void main() => runApp(MyApp());
const simpleTaskKey = "be.tramckrijte.workmanagerExample.simpleTask";
const rescheduledTaskKey = "be.tramckrijte.workmanagerExample.rescheduledTask";
const failedTaskKey = "be.tramckrijte.workmanagerExample.failedTask";
const simpleDelayedTask = "be.tramckrijte.workmanagerExample.simpleDelayedTask";
const simplePeriodicTask = "be.tramckrijte.workmanagerExample.simplePeriodicTask";
const simplePeriodic1HourTask = "be.tramckrijte.workmanagerExample.simplePeriodic1HourTask";
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
switch (task) {
case simpleTaskKey:
print("$simpleTaskKey was executed. inputData = $inputData");
final prefs = await SharedPreferences.getInstance();
prefs.setBool("test", true);
print("Bool from prefs: ${prefs.getBool("test")}");
break;
case rescheduledTaskKey:
final key = inputData!['key']!;
final prefs = await SharedPreferences.getInstance();
if (prefs.containsKey('unique-$key')) {
print('has been running before, task is successful');
return true;
} else {
await prefs.setBool('unique-$key', true);
print('reschedule task');
return false;
}
case failedTaskKey:
print('failed task');
return Future.error('failed');
case simpleDelayedTask:
print("$simpleDelayedTask was executed");
break;
case simplePeriodicTask:
print("$simplePeriodicTask was executed");
break;
case simplePeriodic1HourTask:
print("$simplePeriodic1HourTask was executed");
break;
case Workmanager.iOSBackgroundTask:
print("The iOS background fetch was triggered");
Directory? tempDir = await getTemporaryDirectory();
String? tempPath = tempDir.path;
print(
"You can access other plugins in the background, for example Directory.getTemporaryDirectory(): $tempPath");
break;
}
return Future.value(true);
});
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Flutter WorkManager Example"),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
"Plugin initialization",
style: Theme.of(context).textTheme.headlineSmall,
),
ElevatedButton(
child: Text("Start the Flutter background service"),
onPressed: () {
Workmanager().initialize(
callbackDispatcher,
isInDebugMode: true,
);
},
),
SizedBox(height: 16),
ElevatedButton(
child: Text("Register OneOff Task"),
onPressed: () {
Workmanager().registerOneOffTask(
simpleTaskKey,
simpleTaskKey,
inputData: <String, dynamic>{
'int': 1,
'bool': true,
'double': 1.0,
'string': 'string',
'array': [1, 2, 3],
},
);
},
),
ElevatedButton(
child: Text("Register rescheduled Task"),
onPressed: () {
Workmanager().registerOneOffTask(
rescheduledTaskKey,
rescheduledTaskKey,
inputData: <String, dynamic>{
'key': Random().nextInt(64000),
},
);
},
),
ElevatedButton(
child: Text("Register failed Task"),
onPressed: () {
Workmanager().registerOneOffTask(
failedTaskKey,
failedTaskKey,
);
},
),
ElevatedButton(
child: Text("Register Delayed OneOff Task"),
onPressed: () {
Workmanager().registerOneOffTask(
simpleDelayedTask,
simpleDelayedTask,
initialDelay: Duration(seconds: 10),
);
}),
SizedBox(height: 8),
ElevatedButton(
child: Text("Register Periodic Task (Android)"),
onPressed: Platform.isAndroid
? () {
Workmanager().registerPeriodicTask(
simplePeriodicTask,
simplePeriodicTask,
initialDelay: Duration(seconds: 10),
);
}
: null),
ElevatedButton(
child: Text("Register 1 hour Periodic Task (Android)"),
onPressed: Platform.isAndroid
? () {
Workmanager().registerPeriodicTask(
simplePeriodicTask,
simplePeriodic1HourTask,
frequency: Duration(hours: 1),
);
}
: null),
SizedBox(height: 16),
Text(
"Task cancellation",
style: Theme.of(context).textTheme.headlineSmall,
),
ElevatedButton(
child: Text("Cancel All"),
onPressed: () async {
await Workmanager().cancelAll();
print('Cancel all tasks completed');
},
),
],
),
),
),
),
);
}
}
调试提示
为了更好地调试后台任务,可以在 executeTask
中使用 try-catch
捕获异常,并记录日志:
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
try {
// 任务逻辑
} catch (e) {
print("Error in background task: $e");
throw Exception(e);
}
return Future.value(true);
});
}
其他功能
- 标签(Tagging):可以为任务设置标签,方便批量取消任务。
- 现有任务策略(Existing Work Policy):指定当相同任务被多次调度时的行为,默认为
KEEP
。 - 约束条件(Constraints):可以设置任务执行的条件,如网络类型、电量状态等。
- 输入数据(InputData):可以为任务传递一些输入数据。
- 重试策略(BackoffPolicy):指定任务失败后的重试策略,默认为指数退避。
通过以上内容,您可以轻松地在 Flutter 应用中管理和调度后台任务。希望这些信息对您有所帮助!
更多关于Flutter后台任务管理插件workmanager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter后台任务管理插件workmanager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用workmanager
插件进行后台任务管理的示例代码。workmanager
是一个强大的插件,它允许你在Flutter应用中调度和执行后台任务,即使在应用被关闭或设备重启后也能继续运行。
1. 添加依赖
首先,你需要在pubspec.yaml
文件中添加workmanager
的依赖:
dependencies:
flutter:
sdk: flutter
workmanager: ^0.7.0 # 请检查最新版本号
然后运行flutter pub get
来安装依赖。
2. 配置Android和iOS
Android
在android/app/src/main/AndroidManifest.xml
中添加必要的权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
在android/app/src/main/kotlin/[your_package_name]/MainActivity.kt
(或对应的Java文件)中,初始化WorkManager:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.flutter.embedding.android.FlutterActivity
import androidx.work.Configuration
import androidx.work.WorkManager
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize WorkManager
val configuration = Configuration.Builder()
.setMinimumLoggingLevel(androidx.work.Logger.LEVEL_INFO)
.build()
WorkManager.initialize(this, configuration)
}
}
iOS
在ios/Runner/Info.plist
中添加必要的后台模式:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>remote-notification</string>
</array>
3. 使用WorkManager
在你的Flutter项目中,你可以通过以下方式使用workmanager
插件来调度和执行后台任务。
初始化WorkManager
在你的Dart文件中,首先导入workmanager
包:
import 'package:workmanager/workmanager.dart';
然后,在应用的入口点(通常是main.dart
)初始化WorkManager:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Workmanager.initialize(
callbackDispatcher, // 回调分发器
handleIntent // 处理intent的回调
);
runApp(MyApp());
}
定义任务
定义一个唯一的任务标识符和任务内容:
const simpleTaskKey = "com.example.flutterapp/simpleTask";
void registerTasks() {
Workmanager.registerOneOffTask(
simpleTaskKey,
"Simple Task Description",
inputData: <String, dynamic>{
'taskDataKey': 'taskDataValue',
},
constraints: Constraints(
requiresBatteryNotLow: true,
requiresCharging: false,
requiresStorageNotLow: true,
requiresDeviceIdle: false,
requiresNetworkType: NetworkType.CONNECTED, // 需要网络连接
deviceIdleMode: DeviceIdleMode.not_required,
isRequiredInitialTask: false,
priority: TaskPriority.high,
storageNotLow: true,
batteryNotLow: true,
)
);
}
回调处理
实现回调分发器和处理intent的回调:
void callbackDispatcher() {
Workmanager.executeTask((task, inputData) async {
// 这里处理任务逻辑
print("Executing task: ${task.taskId}");
if (task.taskId == simpleTaskKey) {
// 处理输入数据
print("Input data: ${inputData['taskDataKey']}");
// 模拟任务执行
await Future.delayed(Duration(seconds: 5));
return Workmanager.resultSuccess();
}
return Workmanager.resultFailure();
});
}
void handleIntent(Intent intent) {
// 处理从后台任务返回的intent(如果需要)
}
启动任务
在应用中的适当位置调用registerTasks
函数来注册并启动任务:
@override
void initState() {
super.initState();
registerTasks();
}
这个示例展示了如何在Flutter项目中使用workmanager
插件来调度和执行后台任务。你可以根据自己的需求修改任务的内容和回调处理逻辑。