You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:41:29