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

Flutter中ReceivePort无法监听flutter_downloader回调数据问题

Flutter Downloader回调数据无法通过ReceivePort接收的问题

问题描述

使用flutter_downloader包时,ReceivePort的listen方法无法接收下载任务的回调数据。已按照要求仅传递原始对象(将DownloadTaskStatus转为value),但问题仍未解决。日志中仅能看到回调方法的输出,listen方法内的日志无输出。

代码示例

final ReceivePort _receivePort = ReceivePort();
int? status;
int? progress;
String? id;

@override
void initState() {
  IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'downloader_send_port');
  _receivePort.listen(
    (data) async {
      Logger().e('task listen data: $data'); // 此处无日志输出
      // setState(() {
      //   id = data[0];
      //   status = data[1];
      //   progress = data[2];
      // });
    },
  );
  FlutterDownloader.registerCallback(downloadCallback);
  super.initState();
}

@override
void dispose() {
  IsolateNameServer.removePortNameMapping('downloader_send_port');
}

@pragma('vm:entry-point')
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
  final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
  Logger().e('task send id: $id');
  Logger().e('task send status: ${status.value}');
  Logger().e('task send progress: $progress');
  send?.send([id, status.value, progress]);
}

日志输出

flutter: ^[[38;5;196m│ ⛔ task send id: io.myair.download.task.73570.1683533984.371354<…>
flutter: ^[[38;5;196m│ ⛔ task send status: 1<…>
flutter: ^[[38;5;196m│ ⛔ task send progress: 0<…>
flutter: ^[[38;5;196m│ ⛔ task send id: io.myair.download.task.73570.1683533984.371354<…>
flutter: ^[[38;5;196m│ ⛔ task send status: 3<…>
flutter: ^[[38;5;196m│ ⛔ task send progress: 100<…>

解决方案

1. 修正initState执行顺序

Flutter要求initState方法必须首先调用super.initState(),否则会导致生命周期异常,影响端口注册和监听的有效性。修改后的initState如下:

@override
void initState() {
  super.initState(); // 移至最开头
  IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'downloader_send_port');
  _receivePort.listen(
    (data) async {
      Logger().e('task listen data: $data');
      setState(() {
        id = data[0];
        status = data[1];
        progress = data[2];
      });
    },
  );
  FlutterDownloader.registerCallback(downloadCallback);
}

2. 完善dispose资源回收

在dispose中关闭ReceivePort,避免资源泄漏,同时确保端口映射被正确移除:

@override
void dispose() {
  IsolateNameServer.removePortNameMapping('downloader_send_port');
  _receivePort.close(); // 添加端口关闭逻辑
  super.dispose();
}

3. 确保FlutterDownloader完成初始化

在main函数中调用FlutterDownloader.initialize(),这是包的必要初始化步骤:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterDownloader.initialize(debug: true); // debug模式可开启日志
  runApp(const MyApp());
}

4. 排查端口查找失败情况

在回调函数中增加日志判断SendPort是否存在,确认端口注册是否成功:

@pragma('vm:entry-point')
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
  final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
  if (send == null) {
    Logger().e('SendPort未找到,无法传递回调数据');
    return;
  }
  Logger().e('task send id: $id');
  Logger().e('task send status: ${status.value}');
  Logger().e('task send progress: $progress');
  send.send([id, status.value, progress]);
}

5. Release模式兼容处理

如果在Release模式运行,确保downloadCallback不会被编译器混淆:

  • 保留@pragma('vm:entry-point')注解,该注解会告诉编译器不要混淆此方法
  • 若开启了代码混淆,在pubspec.yaml中确保相关代码不被混淆(或直接关闭混淆测试)

内容的提问来源于stack exchange,提问作者Veronika Haichenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 07:10:39