Flutter Background_Fetch重启设备后无法更新Android Widget问题
问题
我开发了一款基于Flutter的应用,使用home_widget库创建Android桌面Widget展示应用内信息,通过flutter background_fetch库定期更新信息,原本功能正常。但重启设备(模拟器或真机)后,即便已设置enableHeadless: true和stopOnTerminate: false,background_fetch的任务仍无法继续执行,Widget会显示重启前最后一次更新的旧信息。
原代码片段
main.dart
import 'package:home_widget/home_widget.dart'; import 'package:background_fetch/background_fetch.dart'; import 'package:logging_to_logcat/logging_to_logcat.dart'; import 'package:logging/logging.dart'; import 'package:flutter/material.dart'; void main() { runApp( const MaterialApp( home: MyApp() ) ); BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask); } // [Android-only] This "Headless Task" is run when the Android app is terminated with `enableHeadless: true` // Be sure to annotate your callback function to avoid issues in release mode on Flutter >= 3.3.0 @pragma('vm:entry-point') void backgroundFetchHeadlessTask(HeadlessTask task) async { String taskId = task.taskId; bool isTimeout = task.timeout; if (isTimeout) { debugPrint("[BackgroundFetch] Headless task timed-out: $taskId"); BackgroundFetch.finish(taskId); return; } HomeWidget.saveWidgetData('refresh_date', "restarted"); HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge'); debugPrint('[BackgroundFetch] Headless event received.'); BackgroundFetch.finish(taskId); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() { return MainPage(); } } class MainPage extends State { @override void initState() { super.initState(); initPlatformState(); BackgroundFetch.start().then((int status) { debugPrint('[BackgroundFetch] start success: $status'); }).catchError((e) { debugPrint('[BackgroundFetch] start FAILURE: $e'); }); HomeWidget.saveWidgetData('refresh_date', "test2"); HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge'); } // Platform messages are asynchronous, so we initialize in an async method. Future<void> initPlatformState() async { // Configure BackgroundFetch. int status = await BackgroundFetch.configure(BackgroundFetchConfig( minimumFetchInterval: 15, stopOnTerminate: false, enableHeadless: true, requiresBatteryNotLow: false, requiresCharging: false, requiresStorageNotLow: false, requiresDeviceIdle: false, requiredNetworkType: NetworkType.ANY, startOnBoot: true, forceAlarmManager: true ), (String taskId) async { // <-- Event handler print("[BackgroundFetch] Event received $taskId"); setState(() { latestUpdate = DateTime.now(); HomeWidget.saveWidgetData('refresh_date', "test"); HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge'); }); BackgroundFetch.finish(taskId); }, (String taskId) async { // <-- Task timeout handler. debugPrint("[BackgroundFetch] TASK TIMEOUT taskId: $taskId"); BackgroundFetch.finish(taskId); }); debugPrint('[BackgroundFetch] configure success: $status'); if (!mounted) return; } }
pubspec.yaml依赖
dependencies: ... home_widget: ^0.1.6 background_fetch: git: url: https://github.com/transistorsoft/flutter_background_fetch
修复方案
1. 调整Headless任务注册时机
将BackgroundFetch.registerHeadlessTask移到runApp之前,确保Flutter引擎初始化时就完成任务注册,避免重启后App未启动时无法触发任务:
void main() { // 优先注册Headless任务 BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask); runApp(const MaterialApp(home: MyApp())); }
2. 补充AndroidManifest必要配置
在android/app/src/main/AndroidManifest.xml中添加开机自启和后台任务权限:
<!-- 开机自启权限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- Android 12+ 精确闹钟权限 --> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.USE_EXACT_ALARM" /> <!-- 在<application>标签内添加BootReceiver --> <receiver android:name="com.transistorsoft.flutterbackgroundfetch.BootReceiver" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.QUICKBOOT_POWERON"/> <!-- 适配部分国产ROM --> <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/> </intent-filter> </receiver>
3. Headless任务中初始化HomeWidget
重启后Headless任务执行时,home_widget可能未完成初始化,导致数据保存失败,需在任务开头添加初始化调用:
@pragma('vm:entry-point') void backgroundFetchHeadlessTask(HeadlessTask task) async { String taskId = task.taskId; bool isTimeout = task.timeout; if (isTimeout) { debugPrint("[BackgroundFetch] Headless task timed-out: $taskId"); BackgroundFetch.finish(taskId); return; } // 初始化HomeWidget await HomeWidget.init(); // 保存并更新Widget数据 HomeWidget.saveWidgetData('refresh_date', DateTime.now().toString()); HomeWidget.updateWidget(name: 'WidgetLarge', iOSName: 'WidgetLarge'); debugPrint('[BackgroundFetch] Headless event received.'); BackgroundFetch.finish(taskId); }
4. 移除重复的BackgroundFetch.start()调用
BackgroundFetch.configure已完成任务配置,无需额外调用start(),删除initState中的这段代码:
// 移除该代码段 BackgroundFetch.start().then((int status) { debugPrint('[BackgroundFetch] start success: $status'); }).catchError((e) { debugPrint('[BackgroundFetch] start FAILURE: $e'); });
5. 手动测试Headless任务
通过ADB命令手动触发任务,验证是否正常执行:
adb shell cmd jobscheduler run -f 你的应用包名 999
执行后查看Logcat输出,确认任务是否触发并更新Widget数据。
内容的提问来源于stack exchange,提问作者muilenheinz
相关产品推荐
相关产品推荐

