Flutter调用writeAsString导出CSV无报错但未生成文件如何解决
问题原因分析
- 权限配置不完整:仅申请了运行时存储权限,未在Android、iOS端的原生配置文件中声明权限,Android 13+版本旧的存储权限已废弃,未适配新权限规则的情况下,运行时权限申请会直接被系统拒绝,不会弹出授权弹窗。
- 权限逻辑有漏洞:当前代码首次判断权限未授权时,仅触发权限申请,没有监听申请结果,用户同意授权后也不会自动执行后续写入逻辑,需要再次点击导出按钮才会执行,大部分用户不会二次点击,自然看不到生成的文件。
- 路径配置不合理:使用
getExternalStorageDirectory()获取的是App专属沙箱目录,该目录默认对其他应用(包括系统文件管理器)不可见,就算写入成功,用户在系统文件管理器中也找不到文件,会误以为写入失败。且代码未提前判断父目录是否存在,父目录缺失时写入会静默失败。 - 缺少异常捕获逻辑:整个写入过程没有加错误捕获,就算出现IO异常、权限异常也不会打印报错,你会误以为代码运行完全正常。
解决步骤
- 第一步:补全原生权限配置
Android端在android/app/src/main/AndroidManifest.xml的<manifest>标签下添加以下权限:
iOS端在<!-- Android 12及以下存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+权限适配 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />ios/Runner/Info.plist的<dict>标签下添加权限声明:<key>NSDocumentDirectoryUsageDescription</key> <string>需要存储权限导出CSV文件</string> - 第二步:修改导出逻辑,适配权限和路径
先在pubspec.yaml添加依赖:device_info_plus: ^9.1.1(版本可以自行替换为最新稳定版),再替换原有的getCsv方法:import 'package:device_info_plus/device_info_plus.dart'; getCsv() async { try { // 分版本申请权限 Map<Permission, PermissionStatus> statuses; if (Platform.isAndroid) { final androidInfo = await DeviceInfoPlugin().androidInfo; if (androidInfo.version.sdkInt >= 33) { statuses = await [ Permission.manageExternalStorage, Permission.readMediaImages, Permission.readMediaVideo, Permission.readMediaAudio ].request(); } else { statuses = await [Permission.storage].request(); } } else { statuses = await [Permission.storage].request(); } // 校验权限是否全部通过 bool allGranted = statuses.values.every((status) => status.isGranted); if (!allGranted) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("权限被拒,无法导出文件"))); } return; } // 获取公共下载目录,文件可以在系统文件管理器的下载分类中看到 Directory? publicDir = await getExternalStoragePublicDirectory(ExternalStorageDirectory.downloads); if (publicDir == null) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("无法获取存储目录"))); } return; } // 确保目录存在 if (!await publicDir.exists()) { await publicDir.create(recursive: true); } final file = File("${publicDir.path}/mycsv.csv"); String csv = const ListToCsvConverter().convert(employeeData); await file.writeAsString(csv); // 导出成功提示 if (mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("导出成功,文件路径:${file.path}"))); } } catch (e) { debugPrint("导出出错:$e"); if (mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("导出失败:$e"))); } } } - 第三步:验证结果
导出成功后可以根据弹窗提示的路径,直接到系统文件管理器的下载目录中找到对应的CSV文件。
内容的提问来源于stack exchange,提问作者Dani
相关产品推荐
相关产品推荐

