Flutter后台任务执行插件background_fetch的使用

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

Flutter background_fetch 插件使用指南

简介

background_fetch 是一个Flutter插件,用于在应用程序处于后台时定期唤醒应用执行一些简短的任务。它会每隔15分钟左右唤醒一次应用,允许您提供一个回调函数 callbackFn 来处理这些背景事件。

iOS 注意事项

  • 无法增加获取事件发生的频率,并且当用户长时间未打开设备或应用程序时,iOS会减少获取事件的发生频率。
  • 当应用程序被终止后,iOS将不再触发事件,因此不存在 stopOnTerminate: false 的情况。
  • scheduleTask 方法似乎只在设备插入电源时触发,并且该方法设计用于低优先级任务,不会如预期般频繁运行。

Android 注意事项

  • 提供了Headless实现,允许在应用程序终止后继续处理事件。

安装插件

在项目的 pubspec.yaml 文件中添加依赖:

dependencies:
  background_fetch: '^1.1.3'

或者从GitHub上安装最新版本:

dependencies:
  background_fetch:
    git:
      url: https://github.com/transistorsoft/flutter_background_fetch

示例代码

下面是一个完整的示例程序,展示了如何配置和使用 background_fetch 插件。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:background_fetch/background_fetch.dart';

// [Android-only] 当应用程序被终止时,此“无头任务”会被执行
void backgroundFetchHeadlessTask(HeadlessTask task) async {
  String taskId = task.taskId;
  bool isTimeout = task.timeout;
  if (isTimeout) {
    print("[BackgroundFetch] Headless task timed-out: $taskId");
    BackgroundFetch.finish(taskId);
    return;
  }
  print('[BackgroundFetch] Headless event received.');
  // 在这里执行你的工作...
  BackgroundFetch.finish(taskId);
}

void main() {
  runApp(new MyApp());

  // 注册接收应用程序终止后的 BackgroundFetch 事件
  BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _enabled = true;
  int _status = 0;
  List<DateTime> _events = [];

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  Future<void> initPlatformState() async {
    // 配置 BackgroundFetch.
    int status = await BackgroundFetch.configure(
      BackgroundFetchConfig(
        minimumFetchInterval: 15,
        stopOnTerminate: false,
        enableHeadless: true,
        requiresBatteryNotLow: false,
        requiresCharging: false,
        requiresStorageNotLow: false,
        requiresDeviceIdle: false,
        requiredNetworkType: NetworkType.NONE,
      ),
      (String taskId) async {
        print("[BackgroundFetch] Event received $taskId");
        setState(() {
          _events.insert(0, DateTime.now());
        });
        BackgroundFetch.finish(taskId);
      },
      (String taskId) async {
        print("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
        BackgroundFetch.finish(taskId);
      },
    );
    print('[BackgroundFetch] configure success: $status');
    setState(() {
      _status = status;
    });

    if (!mounted) return;
  }

  void _onClickEnable(bool enabled) {
    setState(() {
      _enabled = enabled;
    });
    if (enabled) {
      BackgroundFetch.start().then((int status) {
        print('[BackgroundFetch] start success: $status');
      }).catchError((e) {
        print('[BackgroundFetch] start FAILURE: $e');
      });
    } else {
      BackgroundFetch.stop().then((int status) {
        print('[BackgroundFetch] stop success: $status');
      });
    }
  }

  void _onClickStatus() async {
    int status = await BackgroundFetch.status;
    print('[BackgroundFetch] status: $status');
    setState(() {
      _status = status;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('BackgroundFetch Example', style: TextStyle(color: Colors.black)),
          backgroundColor: Colors.amberAccent,
          brightness: Brightness.light,
          actions: <Widget>[
            Switch(value: _enabled, onChanged: _onClickEnable),
          ],
        ),
        body: Container(
          color: Colors.black,
          child: ListView.builder(
              itemCount: _events.length,
              itemBuilder: (BuildContext context, int index) {
                DateTime timestamp = _events[index];
                return InputDecorator(
                  decoration: InputDecoration(
                    contentPadding: EdgeInsets.only(left: 10.0, top: 10.0, bottom: 0.0),
                    labelStyle: TextStyle(color: Colors.amberAccent, fontSize: 20.0),
                    labelText: "[background fetch event]",
                  ),
                  child: Text(timestamp.toString(), style: TextStyle(color: Colors.white, fontSize: 16.0)),
                );
              }),
        ),
        bottomNavigationBar: BottomAppBar(
          child: Row(
            children: <Widget>[
              RaisedButton(onPressed: _onClickStatus, child: Text('Status')),
              Container(child: Text("$_status"), margin: EdgeInsets.only(left: 20.0))
            ],
          ),
        ),
      ),
    );
  }
}

执行自定义任务

除了默认的背景获取任务外,还可以通过 scheduleTask 方法安排一次性或周期性的任务。需要注意的是,在iOS上,scheduleTask 只有在设备充电时才会运行,并且设计为低优先级任务,不能保证按需频繁运行。

// Step 1:  Configure BackgroundFetch as usual.
int status = await BackgroundFetch.configure(
  BackgroundFetchConfig(
    minimumFetchInterval: 15,
  ),
  (String taskId) async {
    print("[BackgroundFetch] taskId: $taskId");

    switch (taskId) {
      case 'com.transistorsoft.customtask':
        print("Received custom task");
        break;
      default:
        print("Default fetch task");
    }
    BackgroundFetch.finish(taskId);
  },
  (String taskId) async {
    print("[BackgroundFetch] TIMEOUT taskId: $taskId");
    BackgroundFetch.finish(taskId);
  },
);

// Step 2:  Schedule a custom "oneshot" task "com.transistorsoft.customtask" to execute 5000ms from now.
BackgroundFetch.scheduleTask(TaskConfig(
  taskId: "com.transistorsoft.customtask",
  delay: 5000,  // milliseconds
));

调试

对于iOS,可以通过Xcode模拟器来测试背景任务是否正常工作。而对于Android,则可以使用adb命令行工具查看日志或模拟事件。

更多详细信息请参阅官方文档和其他相关资源链接。


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

1 回复

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


当然,下面是一个关于如何在Flutter应用中使用background_fetch插件来执行后台任务的示例代码。这个插件允许应用在后台定期执行某些任务,例如获取位置更新、同步数据等。

首先,确保你已经将background_fetch插件添加到你的Flutter项目中。你可以在pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  background_fetch: ^0.x.x  # 请使用最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你需要配置并启动后台任务。以下是一个完整的示例:

  1. main.dart文件中配置background_fetch
import 'package:flutter/material.dart';
import 'package:background_fetch/background_fetch.dart';

void main() {
  runApp(MyApp());
  configureBackgroundFetch();
}

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

void configureBackgroundFetch() async {
  // 等待背景任务完成配置
  BackgroundFetch.configure(
    MinimumFetchInterval.FIFTEEN_MINUTES,
    enableHeadless: true,
    stopOnTerminate: false,
    requiresBatteryNotLow: false,
    requiresCharging: false,
    requiresStorageNotLow: false,
    requiresDeviceIdle: false,
    jobId: 'com.example.backgroundfetch',
    onReceive: (taskId) async {
      // 这里执行后台任务
      print("[BackgroundFetch] taskId: $taskId");
      
      // 模拟任务执行(例如,获取位置)
      await performBackgroundTask();
      
      // 完成任务后必须调用finish
      BackgroundFetch.finish(taskId);
    },
  ).then((String status) {
    print("[BackgroundFetch] configure success: $status");
  }).catchError((error) {
    print("[BackgroundFetch] configure ERROR: $error");
  });
}

Future<void> performBackgroundTask() async {
  // 这里放置你的后台任务逻辑
  // 例如,获取位置、同步数据等
  await Future.delayed(Duration(seconds: 5)); // 模拟任务执行时间
  print("[BackgroundTask] Performing background task...");
}
  1. 配置AndroidManifest.xml(如果需要):

确保你的AndroidManifest.xml文件中有必要的权限,特别是如果你需要访问位置或网络。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- 其他配置 -->

</manifest>
  1. 添加Headless Task支持(可选,但推荐):

如果你的后台任务需要在应用未运行时执行(例如,设备重启后),你需要创建一个Headless Task。

创建一个新的Dart文件,例如headless_task.dart

import 'package:background_fetch/background_fetch.dart';

void headlessTask(String taskId) async {
  print("[HeadlessTask] taskId: $taskId");
  
  // 执行你的后台任务逻辑
  await performBackgroundTask();
  
  // 完成任务后必须调用finish
  BackgroundFetch.finish(taskId);
}

然后在你的main.dart文件中注册这个Headless Task:

void main() {
  BackgroundFetch.registerHeadlessTask(headlessTask);
  runApp(MyApp());
  configureBackgroundFetch();
}

这个示例展示了如何在Flutter应用中使用background_fetch插件来配置和执行后台任务。请注意,后台任务的执行频率和可靠性可能受到操作系统和设备设置的影响,因此在实际应用中可能需要进一步的测试和调优。

回到顶部