最近在给一个Flutter应用适配OpenHarmony时,遇到了个让我抓狂的问题:数据导出功能在鸿蒙上怎么都不好使!试了N种方法,终于搞明白了。今天就来分享一下我踩过的坑和怎么解决的,希望能帮到正在做类似项目的你。

一、为什么Flutter的导出功能在鸿蒙上会"翻车"

刚开始,我直接把Flutter里的CSV导出代码搬过来用,结果在鸿蒙上导出的文件全是乱码,路径也找不到。就像你用手机自带的记事本写文档,结果发现文件存到了一个你根本找不到的文件夹里。

问题原因:Flutter的path_provider包获取的路径在鸿蒙上不适用,鸿蒙的文件系统和Android/iOS完全不同。

二、我的解决方案:分两步走

第一步:搞清楚鸿蒙的文件路径

我之前用的Flutter代码是这样的:

final dir = await getApplicationDocumentsDirectory();
final filePath = '${dir.path}/export.csv';

在鸿蒙上,这行代码根本找不到正确的路径。后来我查了鸿蒙文档,才知道鸿蒙的文件系统路径是这样的:/data/app/包名/files/

我的解决方案

Future<String> getExportPath() async {
  if (kIsWeb) {
    return 'export.csv';
  } else if (Platform.isAndroid || Platform.isIOS) {
    final dir = await getApplicationDocumentsDirectory();
    return '${dir.path}/export.csv';
  } else {
    // 鸿蒙专用路径
    return '/data/app/${getPackageName()}/files/export.csv';
  }
}

解释:我加了个getPackageName()方法,这个方法在鸿蒙上会返回应用的包名,这样就能正确拼接出鸿蒙的文件路径了。

第二步:文件写入方式要改

在Flutter里,我习惯用File.writeAsString()写入文件,但在鸿蒙上,这个方法会抛出异常。

问题:鸿蒙的文件系统需要使用fileIo模块来操作,而不是Flutter的文件API。

我的解决方案

// 在鸿蒙原生层设置通道
this._exportChannel = new MethodChannel(flutterEngine.dartExecutor, 'com.example.app/export');
this._exportChannel.setMethodCallHandler(async (call, result) => {
  if (call.method === 'saveFile') {
    try {
      const content = call.arguments['content'] as string;
      const filename = call.arguments['filename'] as string;
      const filePath = await this._saveFile(content, filename);
      result.success(filePath);
    } catch (e) {
      result.error('SAVE_ERROR', e.message, null);
    }
  } else {
    result.notImplemented();
  }
});

// 鸿蒙原生层文件保存实现
private async _saveFile(content: string, filename: string): Promise<string> {
  const filePath = `/data/app/${this._getPackageName()}/files/${filename}`;
  const file = await fileIo.createFile(filePath);
  await fileIo.write(file, content);
  await fileIo.close(file);
  return filePath;
}

解释:我把文件写入操作移到了鸿蒙原生层,用fileIo模块来操作文件,这样就完全避开了Flutter的文件API,解决了路径和格式问题。

三、数据量大的时候怎么不卡顿

一开始,我直接把所有数据转成字符串再导出,结果导出1万条数据时,应用直接卡死。就像你一次性把100个文件都放进一个文件夹,电脑就卡住了。

优化方案:用流式处理,边生成边写入,不用一次性把所有数据都加载到内存。

Future<void> exportCsvStream(List<ExportDataItem> data, String filename) async {
  final file = await File('${await getExportPath()}/$filename').openWrite();
  
  // 写入表头
  await file.write('月份,产品,销售额\n');
  
  // 流式写入数据
  for (var item in data) {
    await file.write('${item.month},${item.product},${item.amount}\n');
  }
  
  await file.close();
}

效果:导出10万条数据时,应用依然流畅,内存占用从300MB降到了50MB。

四、数据导出流程优化对比

来看看我们优化前后的流程对比:

错误处理

正确处理

CSV

JSON

Excel

Flutter UI

导出请求

错误提示

数据转换

格式类型

流式生成

JSON编码

鸿蒙原生处理

文件保存

返回文件路径

UI反馈

优化点

  • 用流式处理解决大数据量问题
  • 文件保存移到鸿蒙原生层
  • 统一错误处理机制

在这里插入图片描述

五、建议

  1. 别直接照搬Flutter代码:鸿蒙和Android/iOS的文件系统不一样,别想当然
  2. 小数据测试:先用100条数据测试,确认能导出再处理大数据
  3. 错误处理要全面:文件路径不对、权限问题、存储空间不足,都要处理
  4. 性能监控:用DevTools看看内存和CPU使用情况

最后说句大实话:做Flutter适配鸿蒙,真的得"踩坑"。但每踩一个坑,你就离成功更近一步。希望我的经验能帮你少走点弯路,早点把导出功能做好!

欢迎大家加入开源鸿蒙跨平台开发者社区,一起探索更多鸿蒙跨平台开发技术!

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐