Flutter后台任务管理插件work的使用

发布于 1周前 作者 h691938207 来自 Flutter

Flutter后台任务管理插件work的使用

work 是一个用于简化 HTTP 请求的 Flutter 插件,基于 dio 实现。它封装了 HTTP 业务接口协议,并提供了一套标准且一致的接口编写与执行流程。

安装

pubspec.yaml 文件中添加以下依赖:

dependencies:
  work: ^7.0.0

简单的 GET 请求实现

class GetWork extends Work<String> {
  const GetWork(this.name, this.age);

  final String name;

  final int age;

  [@override](/user/override)
  FutureOr<dynamic> onFillParams(WorkData<String> data) => {
        'name': name,
        'age': age,
      };

  [@override](/user/override)
  String? onRequestSuccessful(WorkData<String> data) =>
      data.response!.data['args'].toString();

  [@override](/user/override)
  String onUrl(WorkData<String> data) => '/get';
}

简单的 POST 请求

class PostJsonWork extends Work<String> {
  const PostJsonWork(this.name, this.age);

  final String name;

  final int age;

  [@override](/user/override)
  HttpMethod onHttpMethod(WorkData<String> data) => HttpMethod.post;

  [@override](/user/override)
  String? onContentType(WorkData<String> data) => 'application/json';

  [@override](/user/override)
  FutureOr<dynamic> onFillParams(WorkData<String> data) => {
    'name': name,
    'age': age,
  };

  [@override](/user/override)
  String? onRequestSuccessful(WorkData<String> data) =>
      data.response!.data['json'].toString();

  [@override](/user/override)
  String onUrl(WorkData<String> data) => '/post';
}

调用接口

final work = await const GetWork('超悟空', 32).start();

print('work result ${work.result} message ${work.message}');

全局设置和通用处理逻辑实现

workConfig 是默认的全局配置,可以在此处设置全局的 dio 配置,也可以在此处设置全局的请求处理逻辑 WorkDelegate

void main() {
  workConfig = WorkConfig(
    dio: Dio(
      BaseOptions(
        connectTimeout: const Duration(seconds: 10),
        receiveTimeout: const Duration(seconds: 30),
        sendTimeout: const Duration(seconds: 30),
        contentType: 'application/x-www-form-urlencoded',
        baseUrl: 'http://httpbin.org/',
      ),
    ),
    delegate: WorkDelegateImp(),
  );
}

处理公司专用响应协议

所有请求和响应数据都在 WorkData 中,可以扩展 WorkData 以添加自定义只读属性方便使用。也可以利用 WorkData.extra 实现写属性扩展。

extension WorkDataExtension<T> on WorkData<T> {
  /// 协议错误码
  int get errorCode => response?.data['errorCode'] ?? 0;

  /// 原始响应结果数据
  dynamic get resultData => response?.data['result'];
}

class WorkDelegateImp extends WorkDelegate {
  [@override](/user/override)
  bool onRequestResult(WorkData data) => data.errorCode == 0;

  [@override](/user/override)
  String? onParamsError(WorkData data) => '参数不合法';

  [@override](/user/override)
  String onNetworkError(data) => '网络连接失败,当前网络不可用';

  [@override](/user/override)
  String onNetworkRequestFailed(data) => '请求失败,服务器异常';

  [@override](/user/override)
  String onParseFailed(data) => '请求失败,服务器异常';

  [@override](/user/override)
  String onRequestFailedMessage(data) =>
      data.response!.data['message'] ?? '操作失败';

  [@override](/user/override)
  String onRequestSuccessfulMessage(data) =>
      data.response!.data['message'] ?? '操作成功';
}

支持请求类型

  • HttpMethod 中的类型:getpostputdeleteheadpatch
  • 上传文件时请实现 Work.onContentType 并设置为 multipart/form-data,参数中的文件需要用 FileUploadFileInfo 类型包装,支持文件列表。
  • 下载文件时可以自己处理字节流,需要实现 Work.onResponseType 并指定自己需要的响应格式,也可以参考 DownloadWork 实现一个快捷下载类,此方式使用 dio.download 下载。

其他

  • Work 中还有很多生命周期方法,用于做有限的接口扩展和定制。
  • 原则是接口数据处理由接口自己(即 Work)处理。
  • 更多具体用法如上传下载等可以参考 测试用例

示例代码

import 'dart:io';

import 'package:json_annotation/json_annotation.dart';
import 'package:work/work.dart';

part 'main.g.dart';

void main() async {
  workConfig = WorkConfig(
    dio: Dio(
      BaseOptions(
        connectTimeout: const Duration(seconds: 10),
        receiveTimeout: const Duration(seconds: 30),
        sendTimeout: const Duration(seconds: 30),
        contentType: 'application/x-www-form-urlencoded',
      ),
    ),
    delegate: WorkDelegateImp(),
  );

  final data = await TestWork('xxx').start();

  if (data.success) {
    print(data.result);
  } else {
    print(data.message);
    print(data.errorCode);
  }

  final download = await DownloadWork(
    path: 'file:/xxx/test.jpg',
    key: 'key',
    resNo: 123,
  ).start();

  if (download.success) {
    // show('file:/xxx/test.jpg')
  }

  final upload = await UploadWork(File('test.jpg')).start();

  if (upload.success) {
    print(upload.result);
  }
}

/// 简化的[WorkData]类实现
///
/// 使用特定的公司接口协议描述。
///
/// ``` http协议
/// 所有接口响应数据格式
///
/// json结构
///
/// {
/// "errorCode":0, // 错误码,成功时返回0
/// "message":null, // 业务消息字符串,可以是成功时用于显示的信息,也可以是失败时的提示信息
/// "result": {}  // 真正响应的有效业务数据,任意类型
/// }
///
/// ```
extension WorkDataExtension<T> on WorkData<T> {
  /// 协议错误码
  int get errorCode => response?.data['errorCode'] ?? 0;

  /// 原始响应结果数据
  dynamic get resultData => response?.data['result'];
}

/// 实现通用处理
///
/// ``` http协议
/// 所有接口响应数据格式
///
/// json结构
///
/// {
/// "errorCode":0, // 错误码
/// "message":null, // 业务消息字符串,可以是成功时用于显示的信息,也可以是失败时的提示信息
/// "result": {}  // 真正响应的有效业务数据,任意类型
/// }
///
/// ```
class WorkDelegateImp extends WorkDelegate {
  [@override](/user/override)
  bool onRequestResult(WorkData data) => data.errorCode == 0;

  [@override](/user/override)
  String? onParamsError(WorkData data) => '参数不合法';

  [@override](/user/override)
  String onNetworkError(data) => '网络连接失败,当前网络不可用';

  [@override](/user/override)
  String onNetworkRequestFailed(data) => '请求失败,服务器异常';

  [@override](/user/override)
  String onParseFailed(data) => '请求失败,服务器异常';

  [@override](/user/override)
  String onRequestFailedMessage(data) =>
      data.response!.data['message'] ?? '操作失败';

  [@override](/user/override)
  String onRequestSuccessfulMessage(data) =>
      data.response!.data['message'] ?? '操作成功';
}

class TestWork extends Work<String> {
  const TestWork(this.param1);

  /// 请求参数1
  final String param1;

  [@override](/user/override)
  FutureOr<dynamic> onFillParams(WorkData<String> data) => {
        'param1': param1,
      };

  [@override](/user/override)
  FutureOr<String?> onRequestSuccessful(WorkData<String> data) {
    return data.resultData['account'];
  }

  [@override](/user/override)
  String onUrl(WorkData<String> data) => 'https://api.example.com/test';
}

[@JsonSerializable](/user/JsonSerializable)()
class DownloadWork extends Work<void> {
  const DownloadWork({
    required this.path,
    required this.key,
    required this.resNo,
  });

  /// 存放路径
  [@JsonKey](/user/JsonKey)(includeToJson: false)
  final String path;

  /// 请求参数key
  final String key;

  /// 请求参数resNo
  final int resNo;

  [@override](/user/override)
  FutureOr<dynamic> onFillParams(WorkData<void> data) =>
      _$DownloadWorkToJson(this);

  [@override](/user/override)
  FutureOr<void> onRequestSuccessful(WorkData<void> data) {}

  [@override](/user/override)
  FutureOr<void> onPostOptions(WorkData<void> data) {
    data.options!.downloadPath = path;
  }

  [@override](/user/override)
  String onRequestFailedMessage(data) => '下载失败';

  [@override](/user/override)
  String onRequestSuccessfulMessage(data) => '下载成功';

  [@override](/user/override)
  String onUrl(WorkData<void> data) => 'https://api.example.com/test.jpg';
}

[@JsonSerializable](/user/JsonSerializable)()
class UploadWork extends Work<String> {
  const UploadWork(this.file);

  /// 需要上传的文件
  [@JsonKey](/user/JsonKey)(toJson: workFileToJsonConvert)
  final File file;

  [@override](/user/override)
  FutureOr<dynamic> onFillParams(WorkData<String> data) =>
      _$UploadWorkToJson(this);

  [@override](/user/override)
  FutureOr<String?> onRequestSuccessful(WorkData<String> data) {
    return data.resultData; // 假设返回的是文件url
  }

  [@override](/user/override)
  String onUrl(WorkData<String> data) => 'https://api.example.com/upload';
}

更多关于Flutter后台任务管理插件work的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter后台任务管理插件work的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,workmanager 是一个流行的插件,用于在后台执行任务。这个插件允许你安排定期或一次性任务,即使应用程序处于关闭状态也能运行。下面是一个使用 workmanager 插件的示例代码,展示如何设置和使用后台任务。

步骤 1: 添加依赖

首先,在你的 pubspec.yaml 文件中添加 workmanager 依赖:

dependencies:
  flutter:
    sdk: flutter
  workmanager: ^0.7.4  # 请检查最新版本

然后运行 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]/Application.kt(或 MainActivity.kt,取决于你的项目结构)中初始化 Workmanager

package com.example.yourapp

import android.app.Application
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.workmanager.WorkmanagerPlugin

class Application : Application() {
    override fun onCreate() {
        super.onCreate()
        WorkmanagerPlugin.initialize(
            this,  // your application context
            WorkmanagerPlugin.CallbackDispatcher(this)  // Dispatcher to handle background callbacks
        )
    }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        // Keep this line to initialize the Workmanager plugin.
        WorkmanagerPlugin.registerWith(flutterEngine.dartExecutor.binaryMessenger)
    }
}

别忘了在 android/app/src/main/AndroidManifest.xml 中指定你的 Application 类:

<application
    android:name=".Application"
    ... >
    ...
</application>

iOS 配置

ios/Runner/Info.plist 中添加以下权限(如果需要):

<key>UIBackgroundModes</key>
<array>
    <string>fetch</string>
    <string>processing</string>
    <string>remote-notification</string>
</array>

ios/Runner/AppDelegate.swift 中初始化 Workmanager(如果你使用的是 Swift):

import UIKit
import Flutter
import workmanager

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        WorkmanagerPlugin.setPluginRegistrantCallback { registry in
            GeneratedPluginRegistrant.register(with: registry)
        }
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

步骤 3: Flutter 代码实现

在你的 Flutter 项目中,使用以下代码来注册和调度后台任务:

import 'package:flutter/material.dart';
import 'package:workmanager/workmanager.dart';

void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {
    // 在这里执行你的后台任务
    print("Background task running: $task");
    print("Input data: $inputData");
    return Future.value(true);
  });
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Workmanager().initialize(
    callbackDispatcher,
    isInDebugMode: true, // 仅在开发模式下设置为 true
  );

  // 注册一个定期任务
  Workmanager().registerOneOffTask(
    "uniqueTaskName",
    "simpleTask", // 这是你在 native 代码中定义的回调任务的名称
    inputData: {'someKey': 'someValue'},
    initialDelay: const Duration(seconds: 10), // 延迟 10 秒后开始任务
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Workmanager Demo'),
        ),
        body: Center(
          child: Text('Check the console for background task logs'),
        ),
      ),
    );
  }
}

注意

  1. 权限:确保在运行时请求必要的权限,尤其是在 Android 上。
  2. 电池优化:某些设备可能会因为电池优化而限制后台任务的执行。
  3. 测试:在真机上进行测试,因为模拟器可能不会触发所有后台任务。

这段代码展示了如何使用 workmanager 插件在 Flutter 应用中注册和执行后台任务。根据你的具体需求,你可以调整任务的调度逻辑和任务执行的代码。

回到顶部